diff --git a/APP_Framework/Applications/connection_app/Kconfig b/APP_Framework/Applications/connection_app/Kconfig index 95563d5c..338c7b38 100755 --- a/APP_Framework/Applications/connection_app/Kconfig +++ b/APP_Framework/Applications/connection_app/Kconfig @@ -1,3 +1,7 @@ menu "connection app" + menuconfig APPLICATION_CONNECTION + bool "Using connection apps" + default n + endmenu diff --git a/APP_Framework/Applications/connection_app/Makefile b/APP_Framework/Applications/connection_app/Makefile index 5948fa6f..cb4403cd 100755 --- a/APP_Framework/Applications/connection_app/Makefile +++ b/APP_Framework/Applications/connection_app/Makefile @@ -1,3 +1,7 @@ SRC_DIR := +ifeq ($(CONFIG_RESOURCES_LWIP),y) + SRC_DIR += socket_demo +endif + include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/APP_Framework/Applications/connection_app/socket_demo/Makefile b/APP_Framework/Applications/connection_app/socket_demo/Makefile new file mode 100755 index 00000000..22a13f97 --- /dev/null +++ b/APP_Framework/Applications/connection_app/socket_demo/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := lwip_tcp_socket_demo.c lwip_udp_socket_demo.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Applications/connection_app/socket_demo/lwip_tcp_socket_demo.c b/APP_Framework/Applications/connection_app/socket_demo/lwip_tcp_socket_demo.c new file mode 100755 index 00000000..08452c8e --- /dev/null +++ b/APP_Framework/Applications/connection_app/socket_demo/lwip_tcp_socket_demo.c @@ -0,0 +1,187 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file tcp_echo_socket_demo.c +* @brief One UDP demo based on LwIP +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-05-29 +*/ +#include +#include +#include "board.h" +#include "sys_arch.h" +#include +#include "lwip/sys.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +char tcp_socket_ip[] = {192, 168, 250, 252}; + +#define TCP_BUF_SIZE 1024 + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void tcp_recv_demo(void *arg) +{ + lw_print("tcp_recv_demo start.\n"); + + int fd = -1; + char *recv_buf; + struct sockaddr_in tcp_addr, server_addr; + int recv_len; + socklen_t addr_len; + + while(1) + { + recv_buf = (char *)malloc(TCP_BUF_SIZE); + if (recv_buf == NULL) + { + lw_print("No memory\n"); + goto __exit; + } + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) + { + lw_print("Socket error\n"); + goto __exit; + } + + tcp_addr.sin_family = AF_INET; + tcp_addr.sin_addr.s_addr = INADDR_ANY; + tcp_addr.sin_port = htons(LOCAL_PORT_SERVER); + memset(&(tcp_addr.sin_zero), 0, sizeof(tcp_addr.sin_zero)); + + if (bind(fd, (struct sockaddr *)&tcp_addr, sizeof(struct sockaddr)) == -1) + { + lw_print("Unable to bind\n"); + goto __exit; + } + + lw_print("tcp bind sucess, start to receive.\n"); + lw_print("\n\nLocal Port:%d\n\n", LOCAL_PORT_SERVER); + + while(1) + { + memset(recv_buf, 0, TCP_BUF_SIZE); + recv_len = recvfrom(fd, recv_buf, TCP_BUF_SIZE, 0, (struct sockaddr *)&server_addr, &addr_len); + lw_pr_info("Receive from : %s\n", inet_ntoa(server_addr.sin_addr)); + lw_pr_info("Receive data : %s\n\n", recv_buf); + sendto(fd, recv_buf, recv_len, 0, (struct sockaddr*)&server_addr, addr_len); + } + + __exit: + if (fd >= 0) + closesocket(fd); + + if (recv_buf) + free(recv_buf); + } +} + +void tcp_socket_recv_run(int argc, char *argv[]) +{ + int result = 0; + pthread_t th_id; + pthread_attr_t attr; + + if(argc == 2) + { + lw_print("lw: [%s] gw %s\n", __func__, argv[1]); + sscanf(argv[1], "%d.%d.%d.%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3]); + } + + ETH_BSP_Config(); + lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + sys_thread_new("tcp_recv_demo", tcp_recv_demo, NULL, 4096, 15); +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), + TCPSocketRecv, tcp_socket_recv_run, TCP recv echo); + +static void tcp_send_demo(void *arg) +{ + int cnt = TEST_LWIP_TIMES; + lw_print("tcp_send_demo start.\n"); + int fd = -1; + char send_msg[128]; + + memset(send_msg, 0, sizeof(send_msg)); + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) + { + lw_print("Socket error\n"); + goto __exit; + } + + struct sockaddr_in tcp_sock; + tcp_sock.sin_family = AF_INET; + tcp_sock.sin_port = htons(TARGET_PORT_CLIENT); + tcp_sock.sin_addr.s_addr = PP_HTONL(LWIP_MAKEU32(tcp_socket_ip[0],tcp_socket_ip[1],tcp_socket_ip[2],tcp_socket_ip[3])); + memset(&(tcp_sock.sin_zero), 0, sizeof(tcp_sock.sin_zero)); + + if (connect(fd, (struct sockaddr *)&tcp_sock, sizeof(struct sockaddr))) + { + lw_print("Unable to connect\n"); + goto __exit; + } + + lw_print("tcp connect success, start to send.\n"); + lw_print("\n\nTarget Port:%d\n\n", tcp_sock.sin_port); + + while (cnt --) + { + lw_print("Lwip client is running.\n"); + snprintf(send_msg, sizeof(send_msg), "TCP test package times %d\r\n", cnt); + sendto(fd, send_msg, strlen(send_msg), 0, (struct sockaddr*)&tcp_sock, sizeof(struct sockaddr)); + lw_print("Send tcp msg: %s ", send_msg); + MdelayKTask(1000); + } + +__exit: + if (fd >= 0) + closesocket(fd); + + return; +} + + +void tcp_socket_send_run(int argc, char *argv[]) +{ + if(argc == 2) + { + lw_print("lw: [%s] gw %s\n", __func__, argv[1]); + sscanf(argv[1], "%d.%d.%d.%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3]); + } + + ETH_BSP_Config(); + lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + sys_thread_new("tcp socket", tcp_send_demo, NULL, 4096, 25); +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0), + TCPSocketSend, tcp_socket_send_run, TCP send demo); + diff --git a/APP_Framework/Applications/connection_app/socket_demo/lwip_udp_socket_demo.c b/APP_Framework/Applications/connection_app/socket_demo/lwip_udp_socket_demo.c new file mode 100755 index 00000000..3f71783a --- /dev/null +++ b/APP_Framework/Applications/connection_app/socket_demo/lwip_udp_socket_demo.c @@ -0,0 +1,209 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file lwip_udp_socket_demo.c +* @brief One UDP demo based on LwIP +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-05-29 +*/ +#include +#include +#include "board.h" +#include "sys_arch.h" +#include "lwip/udp.h" +#include "lwip/opt.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +extern char udp_target[]; +static struct udp_pcb *udpecho_raw_pcb; +char udp_socket_ip[] = {192, 168, 250, 252}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +#include +#include "lwip/sys.h" + +#define LWIP_UDP_TASK_STACK 4096 +#define LWIP_UDP_TASK_PRIO 25 +#define UDP_BUF_SIZE 1024 + +static void udp_recv_demo(void *arg) +{ + lw_print("udp_recv_demo start.\n"); + + int socket_fd = -1; + char *recv_buf; + struct sockaddr_in udp_addr, server_addr; + int recv_len; + socklen_t addr_len; + + while(1) + { + recv_buf = (char *)malloc(UDP_BUF_SIZE); + if (recv_buf == NULL) + { + lw_print("No memory\n"); + goto __exit; + } + + socket_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (socket_fd < 0) + { + lw_print("Socket error\n"); + goto __exit; + } + + udp_addr.sin_family = AF_INET; + udp_addr.sin_addr.s_addr = INADDR_ANY; + udp_addr.sin_port = htons(LOCAL_PORT_SERVER); + memset(&(udp_addr.sin_zero), 0, sizeof(udp_addr.sin_zero)); + + if (bind(socket_fd, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr)) == -1) + { + lw_print("Unable to bind\n"); + goto __exit; + } + + lw_print("UDP bind sucess, start to receive.\n"); + lw_print("\n\nLocal Port:%d\n\n", LOCAL_PORT_SERVER); + + while(1) + { + memset(recv_buf, 0, UDP_BUF_SIZE); + recv_len = recvfrom(socket_fd, recv_buf, UDP_BUF_SIZE, 0, (struct sockaddr *)&server_addr, &addr_len); + lw_print("Receive from : %s\n", inet_ntoa(server_addr.sin_addr)); + lw_print("Receive data : %s\n\n", recv_buf); + sendto(socket_fd, recv_buf, recv_len, 0, (struct sockaddr*)&server_addr, addr_len); + } + + __exit: + if (socket_fd >= 0) + closesocket(socket_fd); + + if (recv_buf) + free(recv_buf); + } +} + +static void udp_recv_demo_thread(void* param) +{ + ETH_BSP_Config(); + lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + sys_thread_new("udp_recv_demo", udp_recv_demo, NULL, LWIP_UDP_TASK_STACK, LWIP_UDP_TASK_PRIO); +} + +void udp_socket_recv_run(int argc, char *argv[]) +{ + int result = 0; + pthread_t th_id; + pthread_attr_t attr; + + if(argc == 2) + { + lw_print("lw: [%s] gw %s\n", __func__, argv[1]); + sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]); + } + + sys_thread_new("udp socket send", udp_recv_demo_thread, NULL, 4096, 15); +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), + UDPSocketRecv, udp_socket_recv_run, UDP recv echo); + +static void udp_send_demo(void *arg) +{ + int cnt = TEST_LWIP_TIMES; + char send_str[128]; + + lw_print("udp_send_demo start.\n"); + + int socket_fd = -1; + memset(send_str, 0, sizeof(send_str)); + + socket_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (socket_fd < 0) + { + lw_print("Socket error\n"); + goto __exit; + } + + struct sockaddr_in udp_sock; + udp_sock.sin_family = AF_INET; + udp_sock.sin_port = htons(TARGET_PORT_CLIENT); + udp_sock.sin_addr.s_addr = PP_HTONL(LWIP_MAKEU32(udp_target[0],udp_target[1],udp_target[2],udp_target[3])); + memset(&(udp_sock.sin_zero), 0, sizeof(udp_sock.sin_zero)); + + if (connect(socket_fd, (struct sockaddr *)&udp_sock, sizeof(struct sockaddr))) + { + lw_print("Unable to connect\n"); + goto __exit; + } + + lw_print("UDP connect success, start to send.\n"); + lw_print("\n\nTarget Port:%d\n\n", udp_sock.sin_port); + + while (cnt --) + { + snprintf(send_str, sizeof(send_str), "UDP test package times %d\r\n", cnt); + sendto(socket_fd, send_str, strlen(send_str), 0, (struct sockaddr*)&udp_sock, sizeof(struct sockaddr)); + lw_pr_info("Send UDP msg: %s ", send_str); + MdelayKTask(1000); + } + +__exit: + if (socket_fd >= 0) + { + closesocket(socket_fd); + } + + return; +} + +static void udp_send_demo_thread(void* param) +{ + ETH_BSP_Config(); + lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + sys_thread_new("udp_send_demo", udp_send_demo, NULL, LWIP_UDP_TASK_STACK, LWIP_UDP_TASK_PRIO); +} + +void udp_socket_send_run(int argc, char *argv[]) +{ + int result = 0; + pthread_t th_id; + pthread_attr_t attr; + + if(argc == 2) + { + lw_print("lw: [%s] gw %s\n", __func__, argv[1]); + sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]); + } + + sys_thread_new("udp socket send", udp_send_demo_thread, NULL, 4096, 15); +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), + UDPSocketSend, udp_socket_send_run, UDP send echo); + diff --git a/APP_Framework/Applications/control_app/Kconfig b/APP_Framework/Applications/control_app/Kconfig index 6128642c..02ddbf10 100755 --- a/APP_Framework/Applications/control_app/Kconfig +++ b/APP_Framework/Applications/control_app/Kconfig @@ -3,6 +3,7 @@ menu "control app" menuconfig APPLICATION_CONTROL bool "Using control apps" default n + depends on SUPPORT_CONTROL_FRAMEWORK endmenu diff --git a/APP_Framework/Applications/control_app/Makefile b/APP_Framework/Applications/control_app/Makefile index e69de29b..e321906d 100755 --- a/APP_Framework/Applications/control_app/Makefile +++ b/APP_Framework/Applications/control_app/Makefile @@ -0,0 +1,11 @@ +SRC_DIR := + +ifeq ($(CONFIG_RESOURCES_LWIP),y) + +ifeq ($(CONFIG_USING_CONTROL_PLC_OPCUA), y) + SRC_DIR += opcua_demo +endif + +endif + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Applications/control_app/opcua_demo/Makefile b/APP_Framework/Applications/control_app/opcua_demo/Makefile new file mode 100755 index 00000000..b595ed06 --- /dev/null +++ b/APP_Framework/Applications/control_app/opcua_demo/Makefile @@ -0,0 +1,3 @@ +SRC_FILES :=opcua_demo.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Applications/control_app/opcua_demo/opcua_demo.c b/APP_Framework/Applications/control_app/opcua_demo/opcua_demo.c new file mode 100755 index 00000000..76634b9d --- /dev/null +++ b/APP_Framework/Applications/control_app/opcua_demo/opcua_demo.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2021 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file ua_demo.c + * @brief Demo for OpcUa function + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.11.11 + */ + +#include +#include +#include "board.h" +#include +#include "open62541.h" +#include "ua_api.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +//#define ua_print KPrintf +#define ua_trace() KPrintf("ua: [%s] %d pass!\n", __func__, __LINE__) + +#define TCP_LOCAL_PORT 4840 + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +const char *test_uri = "opc.tcp://192.168.250.5:4840"; +const char *test_cb_str = "tcp client connected\r\n"; + +char test_ua_gw[] = {192, 168, 250, 5}; + +static pthread_t eth_input_id = 0; +static pthread_t ua_demo_id; + +/******************************************************************************* + * Code + ******************************************************************************/ + +void *test_ua_get_server_info(void *param); + +static void test_ua_connect(void *arg) +{ + struct netif net; + UA_StatusCode retval; + + UA_Client *client = UA_Client_new(); + + if (client == NULL) + { + ua_print("ua: [%s] tcp client null\n", __func__); + return; + } + + UA_ClientConfig *config = UA_Client_getConfig(client); + UA_ClientConfig_setDefault(config); + + retval = UA_Client_connect(client, test_uri); + if (retval != UA_STATUSCODE_GOOD) + { + ua_print("ua: [%s] ret %x\n", __func__, retval); + } + + ua_print("ua: [%s] start Ua Test!\n", __func__); + UA_Client_disconnect(client); + UA_Client_delete(client); +} + +void test_ua_connect_thr(void *arg) +{ + ETH_BSP_Config(); + lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_gw); + test_ua_connect(NULL); +} + +void test_sh_ua_connect(void) +{ + int result = 0; + pthread_t th_id; + pthread_attr_t attr; + sys_thread_new("ua test", test_ua_connect_thr, NULL, 4096, 15); +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0), + UaConnect, test_sh_ua_connect, Test Opc UA connection); + +void *test_ua_get_server_info(void *param) +{ + UA_Client *client = UA_Client_new(); + + ua_print("ua: [%s] start ...\n", __func__); + + if (client == NULL) + { + ua_print("ua: [%s] tcp client null\n", __func__); + return NULL; + } + + UA_ClientConfig *config = UA_Client_getConfig(client); + UA_ClientConfig_setDefault(config); + + UA_StatusCode retval = UA_Client_connect(client, OPC_SERVER); + if(retval != UA_STATUSCODE_GOOD) { + ua_print("ua: [%s] connect failed %#x\n", __func__, retval); + UA_Client_delete(client); + return NULL; + } + + ua_print("ua: [%s] connect ok!\n", __func__); + + ua_read_time(client); + ua_get_server_info(client); + + /* Clean up */ + UA_Client_disconnect(client); + UA_Client_delete(client); /* Disconnects the client internally */ +} + +void *test_ua_get_server_info_thr(void *arg) +{ + ETH_BSP_Config(); + lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_gw); + test_ua_get_server_info(NULL); +} + +void *test_sh_ua_get_server_info(void *param) +{ + int result = 0; + pthread_attr_t attr; + + attr.schedparam.sched_priority = 15; + attr.stacksize = 4096; + + result = pthread_create(&ua_demo_id, &attr, test_ua_get_server_info_thr, NULL); + if (0 == result) { + lw_print("test_ua_get_server_info %d successfully!\n", __func__, ua_demo_id); + } else { + lw_print("test_ua_get_server_info failed! error code is %d\n", __func__, result); + } +} + +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0), + UaGetInfo, test_sh_ua_get_server_info, Get information from OpcUA server); + diff --git a/APP_Framework/Framework/control/Kconfig b/APP_Framework/Framework/control/Kconfig index 3ac0ef89..9a4f5e4b 100755 --- a/APP_Framework/Framework/control/Kconfig +++ b/APP_Framework/Framework/control/Kconfig @@ -1,4 +1,8 @@ menuconfig SUPPORT_CONTROL_FRAMEWORK bool "support control framework" default n - select TRANSFORM_LAYER_ATTRIUBUTE \ No newline at end of file + select TRANSFORM_LAYER_ATTRIUBUTE + +if SUPPORT_CONTROL_FRAMEWORK + source "$APP_DIR/Framework/control/plc/interoperability/Kconfig" +endif diff --git a/APP_Framework/Framework/control/Makefile b/APP_Framework/Framework/control/Makefile index f75f2e60..3b00b033 100755 --- a/APP_Framework/Framework/control/Makefile +++ b/APP_Framework/Framework/control/Makefile @@ -1,3 +1,3 @@ -SRC_DIR := +SRC_DIR := shared plc include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/control/plc/Makefile b/APP_Framework/Framework/control/plc/Makefile new file mode 100755 index 00000000..6c76af19 --- /dev/null +++ b/APP_Framework/Framework/control/plc/Makefile @@ -0,0 +1,4 @@ +SRC_DIR := shared interoperability + +include $(KERNEL_ROOT)/compiler.mk + diff --git a/APP_Framework/Framework/control/plc/interoperability/Kconfig b/APP_Framework/Framework/control/plc/interoperability/Kconfig new file mode 100755 index 00000000..66ae5f18 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/Kconfig @@ -0,0 +1,6 @@ + +menuconfig USING_CONTROL_PLC_OPCUA + bool "PLC support OPCUA" + default y + depends on RESOURCES_LWIP + diff --git a/APP_Framework/Framework/control/plc/interoperability/Makefile b/APP_Framework/Framework/control/plc/interoperability/Makefile new file mode 100755 index 00000000..7f542f71 --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/Makefile @@ -0,0 +1,13 @@ +SRC_DIR := + +ifeq ($(CONFIG_RESOURCES_LWIP),y) + +ifeq ($(CONFIG_USING_CONTROL_PLC_OPCUA), y) + SRC_DIR += opcua +endif + +endif + +SRC_FILES += interoperability.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/control/plc/interoperability/interoperability.c b/APP_Framework/Framework/control/plc/interoperability/interoperability.c new file mode 100755 index 00000000..74c46fad --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/interoperability.c @@ -0,0 +1,30 @@ +/* +* Copyright (c) 2021 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + + +void ctrl_interop_init(void) +{ +} + +void ctrl_interop_connect(void) +{ +} + +void ctrl_interop_enable(void) +{ +} + +void ctrl_interop_disable(void) +{ +} + + diff --git a/APP_Framework/Framework/control/plc/interoperability/opcua/Kconfig b/APP_Framework/Framework/control/plc/interoperability/opcua/Kconfig new file mode 100755 index 00000000..e69de29b diff --git a/APP_Framework/Framework/control/plc/interoperability/opcua/Makefile b/APP_Framework/Framework/control/plc/interoperability/opcua/Makefile new file mode 100755 index 00000000..531b181e --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/opcua/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := ua_data.c open62541.c ua_client.c ua_server.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Framework/control/plc/interoperability/opcua/open62541.c b/APP_Framework/Framework/control/plc/interoperability/opcua/open62541.c new file mode 100755 index 00000000..961f243a --- /dev/null +++ b/APP_Framework/Framework/control/plc/interoperability/opcua/open62541.c @@ -0,0 +1,71784 @@ +/* THIS IS A SINGLE-FILE DISTRIBUTION CONCATENATED FROM THE OPEN62541 SOURCES + * visit http://open62541.org/ for information about this software + * Git-Revision: v1.2.2-506-g998e2523-dirty + */ + +/* + * Copyright (C) 2014-2021 the contributors as stated in the AUTHORS file + * + * This file is part of open62541. open62541 is free software: you can + * redistribute it and/or modify it under the terms of the Mozilla Public + * 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. + */ + +/* + * Copyright (c) 2021 AIIT XUOS Lab + * XiUOS is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * @file open62541.c + * @brief Support OPCUA protocol + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.12.15 + */ + +#ifndef UA_DYNAMIC_LINKING_EXPORT +# define UA_DYNAMIC_LINKING_EXPORT +# define MDNSD_DYNAMIC_LINKING +#endif + +/* Disable security warnings for BSD sockets on MSVC */ +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +# define _CRT_SECURE_NO_WARNINGS +#endif + +#include "open62541.h" + +#define ua_print KPrintf +#define ua_trace() KPrintf("ua: [%s] line %d checked!\n", __func__, __LINE__) + +#if LWIP_DNS + +#else + +/* input flags for struct addrinfo */ +#define AI_PASSIVE 0x01 +#define AI_CANONNAME 0x02 +#define AI_NUMERICHOST 0x04 +#define AI_NUMERICSERV 0x08 +#define AI_V4MAPPED 0x10 +#define AI_ALL 0x20 +#define AI_ADDRCONFIG 0x40 + +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Address family of socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol of socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address of socket. */ + char *ai_canonname; /* Canonical name of service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; + +#endif + +/**** amalgamated original file "/deps/open62541_queue.h" ****/ + +/* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * 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 } + +#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) do { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} while(0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (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 "/deps/pcg_basic.h" ****/ + +/* + * PCG Random Number Generation for C. + * + * Copyright 2014 Melissa O'Neill + * + * 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 "/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 __secs_to_tm(long long t, struct mytm *tm); +long long __tm_to_secs(const struct mytm *tm); + + +/**** amalgamated original file "/deps/base64.h" ****/ + +#ifndef UA_BASE64_H_ +#define UA_BASE64_H_ + + +_UA_BEGIN_DECLS + +#include + +/** + * base64_encode - Base64 encode + * @src: Data to be encoded + * @len: Length of the data to be encoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of encoded data, + * or %NULL on failure. The output is NOT Null-terminated. */ +unsigned char * +UA_base64(const unsigned char *src, size_t len, size_t *out_len); + +/** + * base64_decode - Base64 decode + * @src: Data to be decoded + * @len: Length of the data to be decoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of decoded data, + * or %NULL on failure. */ +unsigned char * +UA_unbase64(const unsigned char *src, size_t len, size_t *out_len); + +_UA_END_DECLS + +#endif /* UA_BASE64_H_ */ + +/**** amalgamated original file "/src/ua_types_encoding_binary.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2015 (c) Sten Grüner + * Copyright 2014, 2017 (c) Florian Palm + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + + +_UA_BEGIN_DECLS + +typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos, + const UA_Byte **bufEnd); + +/* Encodes the scalar value described by type in the binary encoding. Encoding + * is thread-safe if thread-local variables are enabled. Encoding is also + * reentrant and can be safely called from signal handlers or interrupts. + * + * @param src The value. Must not be NULL. + * @param type The value type. Must not be NULL. + * @param bufPos Points to a pointer to the current position in the encoding + * buffer. Must not be NULL. The pointer is advanced by the number of + * encoded bytes, or, if the buffer is exchanged, to the position in the + * new buffer. + * @param bufEnd Points to a pointer to the end of the encoding buffer (encoding + * always stops before *buf_end). Must not be NULL. The pointer is + * changed when the buffer is exchanged. + * @param exchangeCallback Called when the end of the buffer is reached. This is + used to send out a message chunk before continuing with the encoding. + Is ignored if NULL. + * @param exchangeHandle Custom data passed into the exchangeCallback. + * @return Returns a statuscode whether encoding succeeded. */ +UA_StatusCode +UA_encodeBinaryInternal(const void *src, const UA_DataType *type, + UA_Byte **bufPos, const UA_Byte **bufEnd, + UA_exchangeEncodeBuffer exchangeCallback, + void *exchangeHandle) + UA_FUNC_ATTR_WARN_UNUSED_RESULT; + +/* Decodes a scalar value described by type from binary encoding. Decoding + * is thread-safe if thread-local variables are enabled. Decoding is also + * reentrant and can be safely called from signal handlers or interrupts. + * + * @param src The buffer with the binary encoded value. Must not be NULL. + * @param offset The current position in the buffer. Must not be NULL. The value + * is advanced as decoding progresses. + * @param dst The target value. Must not be NULL. The target is assumed to have + * size type->memSize. The value is reset to zero before decoding. If + * decoding fails, members are deleted and the value is reset (zeroed) + * again. + * @param type The value type. Must not be NULL. + * @param customTypesSize The number of non-standard datatypes contained in the + * customTypes array. + * @param customTypes An array of non-standard datatypes (not included in + * UA_TYPES). Can be NULL if customTypesSize is zero. + * @return Returns a statuscode whether decoding succeeded. */ +UA_StatusCode +UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset, + void *dst, const UA_DataType *type, + const UA_DataTypeArray *customTypes) + UA_FUNC_ATTR_WARN_UNUSED_RESULT; + +const UA_DataType * +UA_findDataTypeByBinary(const UA_NodeId *typeId); + +_UA_END_DECLS + + +/**** amalgamated original file "/src/ua_util_internal.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + * Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes) + */ + + +#define UA_INTERNAL + + +_UA_BEGIN_DECLS + +/* Macro-Expand for MSVC workarounds */ +#define UA_MACRO_EXPAND(x) x + +/* Print a NodeId in logs */ +#define UA_LOG_NODEID_INTERNAL(NODEID, LOG) \ + do { \ + UA_String nodeIdStr = UA_STRING_NULL; \ + UA_NodeId_print(NODEID, &nodeIdStr); \ + LOG; \ + UA_String_clear(&nodeIdStr); \ + } while(0) + +#if UA_LOGLEVEL <= 100 +# define UA_LOG_NODEID_TRACE(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_TRACE(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 200 +# define UA_LOG_NODEID_DEBUG(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_DEBUG(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 300 +# define UA_LOG_NODEID_INFO(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_INFO(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 400 +# define UA_LOG_NODEID_WARNING(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_WARNING(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 500 +# define UA_LOG_NODEID_ERROR(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_ERROR(NODEID, LOG) +#endif + +#if UA_LOGLEVEL <= 600 +# define UA_LOG_NODEID_FATAL(NODEID, LOG) \ + UA_LOG_NODEID_INTERNAL(NODEID, LOG) +#else +# define UA_LOG_NODEID_FATAL(NODEID, LOG) +#endif + +/* Short names for integer. These are not exposed on the public API, since many + * user-applications make the same definitions in their headers. */ +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; + +/** + * Error checking macros + */ + +static UA_INLINE UA_Boolean +isGood(UA_StatusCode code) { + return code == UA_STATUSCODE_GOOD; +} + +static UA_INLINE UA_Boolean +isNonNull(const void *ptr) { + return ptr != NULL; +} + +static UA_INLINE UA_Boolean +isTrue(uint8_t expr) { + return expr; +} + +#define UA_CHECK(A, EVAL_ON_ERROR) \ + do { \ + if(UA_UNLIKELY(!isTrue(A))) { \ + EVAL_ON_ERROR; \ + } \ + } while(0) + +#define UA_CHECK_STATUS(STATUSCODE, EVAL_ON_ERROR) \ + UA_CHECK(isGood(STATUSCODE), EVAL_ON_ERROR) + +#define UA_CHECK_MEM(STATUSCODE, EVAL_ON_ERROR) \ + UA_CHECK(isNonNull(STATUSCODE), EVAL_ON_ERROR) + +#ifdef UA_DEBUG_FILE_LINE_INFO +#define UA_CHECK_LOG_INTERNAL(A, STATUSCODE, EVAL, LOG, LOGGER, CAT, MSG, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK(A, LOG(LOGGER, CAT, "" MSG "%s (%s:%d: statuscode: %s)", __VA_ARGS__, \ + __FILE__, __LINE__, UA_StatusCode_name(STATUSCODE)); \ + EVAL)) +#else +#define UA_CHECK_LOG_INTERNAL(A, STATUSCODE, EVAL, LOG, LOGGER, CAT, MSG, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK(A, LOG(LOGGER, CAT, "" MSG "%s (statuscode: %s)", __VA_ARGS__, \ + UA_StatusCode_name(STATUSCODE)); \ + EVAL)) +#endif + +#define UA_CHECK_LOG(A, EVAL, LEVEL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(A, UA_STATUSCODE_BAD, EVAL, UA_LOG_##LEVEL, \ + LOGGER, CAT, __VA_ARGS__, "")) + +#define UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, LEVEL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(isGood(STATUSCODE), STATUSCODE, \ + EVAL, UA_LOG_##LEVEL, LOGGER, CAT, \ + __VA_ARGS__, "")) + +#define UA_CHECK_MEM_LOG(PTR, EVAL, LEVEL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(isNonNull(PTR), UA_STATUSCODE_BADOUTOFMEMORY, \ + EVAL, UA_LOG_##LEVEL, LOGGER, CAT, \ + __VA_ARGS__, "")) + +/** + * Check Macros + * Usage examples: + * + * void *data = malloc(...); + * UA_CHECK(data, return error); + * + * UA_StatusCode rv = some_func(...); + * UA_CHECK_STATUS(rv, return rv); + * + * UA_Logger *logger = &server->config.logger; + * rv = bar_func(...); + * UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SERVER, "msg & args %s", "arg"); + */ +#define UA_CHECK_FATAL(A, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_ERROR(A, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_WARN(A, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_INFO(A, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, INFO, LOGGER, CAT, __VA_ARGS__)) + +#define UA_CHECK_STATUS_FATAL(STATUSCODE, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_STATUS_ERROR(STATUSCODE, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_STATUS_WARN(STATUSCODE, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_STATUS_INFO(STATUSCODE, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, INFO, LOGGER, CAT, __VA_ARGS__)) + +#define UA_CHECK_MEM_FATAL(PTR, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_MEM_LOG(PTR, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_MEM_ERROR(PTR, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_MEM_LOG(PTR, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_MEM_WARN(PTR, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_MEM_LOG(PTR, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__)) +#define UA_CHECK_MEM_INFO(PTR, EVAL, LOGGER, CAT, ...) \ + UA_MACRO_EXPAND( \ + UA_CHECK_MEM_LOG(PTR, EVAL, INFO, LOGGER, CAT, __VA_ARGS__)) + +/** + * Utility Functions + * ----------------- */ + +const UA_DataType * +UA_findDataTypeWithCustom(const UA_NodeId *typeId, + const UA_DataTypeArray *customTypes); + +/* Get the number of optional fields contained in an structure type */ +size_t UA_EXPORT +getCountOfOptionalFields(const UA_DataType *type); + +/* Dump packet for debugging / fuzzing */ +#ifdef UA_DEBUG_DUMP_PKGS +void UA_EXPORT +UA_dump_hex_pkg(UA_Byte* buffer, size_t bufferLen); +#endif + +/* Unions that represent any of the supported request or response message */ +typedef union { + UA_RequestHeader requestHeader; + UA_FindServersRequest findServersRequest; + UA_GetEndpointsRequest getEndpointsRequest; +#ifdef UA_ENABLE_DISCOVERY +# ifdef UA_ENABLE_DISCOVERY_MULTICAST + UA_FindServersOnNetworkRequest findServersOnNetworkRequest; +# endif + UA_RegisterServerRequest registerServerRequest; + UA_RegisterServer2Request registerServer2Request; +#endif + UA_OpenSecureChannelRequest openSecureChannelRequest; + UA_CreateSessionRequest createSessionRequest; + UA_ActivateSessionRequest activateSessionRequest; + UA_CloseSessionRequest closeSessionRequest; + UA_AddNodesRequest addNodesRequest; + UA_AddReferencesRequest addReferencesRequest; + UA_DeleteNodesRequest deleteNodesRequest; + UA_DeleteReferencesRequest deleteReferencesRequest; + UA_BrowseRequest browseRequest; + UA_BrowseNextRequest browseNextRequest; + UA_TranslateBrowsePathsToNodeIdsRequest translateBrowsePathsToNodeIdsRequest; + UA_RegisterNodesRequest registerNodesRequest; + UA_UnregisterNodesRequest unregisterNodesRequest; + UA_ReadRequest readRequest; + UA_WriteRequest writeRequest; +#ifdef UA_ENABLE_HISTORIZING + UA_HistoryReadRequest historyReadRequest; + UA_HistoryUpdateRequest historyUpdateRequest; +#endif +#ifdef UA_ENABLE_METHODCALLS + UA_CallRequest callRequest; +#endif +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_CreateMonitoredItemsRequest createMonitoredItemsRequest; + UA_DeleteMonitoredItemsRequest deleteMonitoredItemsRequest; + UA_ModifyMonitoredItemsRequest modifyMonitoredItemsRequest; + UA_SetMonitoringModeRequest setMonitoringModeRequest; + UA_CreateSubscriptionRequest createSubscriptionRequest; + UA_ModifySubscriptionRequest modifySubscriptionRequest; + UA_SetPublishingModeRequest setPublishingModeRequest; + UA_PublishRequest publishRequest; + UA_RepublishRequest republishRequest; + UA_DeleteSubscriptionsRequest deleteSubscriptionsRequest; +#endif +} UA_Request; + +typedef union { + UA_ResponseHeader responseHeader; + UA_FindServersResponse findServersResponse; + UA_GetEndpointsResponse getEndpointsResponse; +#ifdef UA_ENABLE_DISCOVERY +# ifdef UA_ENABLE_DISCOVERY_MULTICAST + UA_FindServersOnNetworkResponse findServersOnNetworkResponse; +# endif + UA_RegisterServerResponse registerServerResponse; + UA_RegisterServer2Response registerServer2Response; +#endif + UA_OpenSecureChannelResponse openSecureChannelResponse; + UA_CreateSessionResponse createSessionResponse; + UA_ActivateSessionResponse activateSessionResponse; + UA_CloseSessionResponse closeSessionResponse; + UA_AddNodesResponse addNodesResponse; + UA_AddReferencesResponse addReferencesResponse; + UA_DeleteNodesResponse deleteNodesResponse; + UA_DeleteReferencesResponse deleteReferencesResponse; + UA_BrowseResponse browseResponse; + UA_BrowseNextResponse browseNextResponse; + UA_TranslateBrowsePathsToNodeIdsResponse translateBrowsePathsToNodeIdsResponse; + UA_RegisterNodesResponse registerNodesResponse; + UA_UnregisterNodesResponse unregisterNodesResponse; + UA_ReadResponse readResponse; + UA_WriteResponse writeResponse; +#ifdef UA_ENABLE_HISTORIZING + UA_HistoryReadResponse historyReadResponse; + UA_HistoryUpdateResponse historyUpdateResponse; +#endif +#ifdef UA_ENABLE_METHODCALLS + UA_CallResponse callResponse; +#endif +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_CreateMonitoredItemsResponse createMonitoredItemsResponse; + UA_DeleteMonitoredItemsResponse deleteMonitoredItemsResponse; + UA_ModifyMonitoredItemsResponse modifyMonitoredItemsResponse; + UA_SetMonitoringModeResponse setMonitoringModeResponse; + UA_CreateSubscriptionResponse createSubscriptionResponse; + UA_ModifySubscriptionResponse modifySubscriptionResponse; + UA_SetPublishingModeResponse setPublishingModeResponse; + UA_PublishResponse publishResponse; + UA_RepublishResponse republishResponse; + UA_DeleteSubscriptionsResponse deleteSubscriptionsResponse; +#endif +} UA_Response; + +/* Do not expose UA_String_equal_ignorecase to public API as it currently only handles + * ASCII strings, and not UTF8! */ +UA_Boolean UA_EXPORT +UA_String_equal_ignorecase(const UA_String *s1, const UA_String *s2); + +/********************/ +/* Encoding Helpers */ +/********************/ + +#define UA_ENCODING_HELPERS(TYPE, UPCASE_TYPE) \ + static UA_INLINE size_t \ + UA_##TYPE##_calcSizeBinary(const UA_##TYPE *src) { \ + return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_##UPCASE_TYPE]); \ + } \ + static UA_INLINE UA_StatusCode \ + UA_##TYPE##_encodeBinary(const UA_##TYPE *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { \ + return UA_encodeBinaryInternal(src, &UA_TYPES[UA_TYPES_##UPCASE_TYPE], \ + bufPos, &bufEnd, NULL, NULL); \ + } \ + static UA_INLINE UA_StatusCode \ + UA_##TYPE##_decodeBinary(const UA_ByteString *src, size_t *offset, UA_##TYPE *dst) { \ + return UA_decodeBinaryInternal(src, offset, dst, \ + &UA_TYPES[UA_TYPES_##UPCASE_TYPE], NULL); \ + } + +UA_ENCODING_HELPERS(Boolean, BOOLEAN) +UA_ENCODING_HELPERS(SByte, SBYTE) +UA_ENCODING_HELPERS(Byte, BYTE) +UA_ENCODING_HELPERS(Int16, INT16) +UA_ENCODING_HELPERS(UInt16, UINT16) +UA_ENCODING_HELPERS(Int32, INT32) +UA_ENCODING_HELPERS(UInt32, UINT32) +UA_ENCODING_HELPERS(Int64, INT64) +UA_ENCODING_HELPERS(UInt64, UINT64) +UA_ENCODING_HELPERS(Float, FLOAT) +UA_ENCODING_HELPERS(Double, DOUBLE) +UA_ENCODING_HELPERS(String, STRING) +UA_ENCODING_HELPERS(DateTime, DATETIME) +UA_ENCODING_HELPERS(Guid, GUID) +UA_ENCODING_HELPERS(ByteString, BYTESTRING) +UA_ENCODING_HELPERS(XmlElement, XMLELEMENT) +UA_ENCODING_HELPERS(NodeId, NODEID) +UA_ENCODING_HELPERS(ExpandedNodeId, EXPANDEDNODEID) +UA_ENCODING_HELPERS(StatusCode, STATUSCODE) +UA_ENCODING_HELPERS(QualifiedName, QUALIFIEDNAME) +UA_ENCODING_HELPERS(LocalizedText, LOCALIZEDTEXT) +UA_ENCODING_HELPERS(ExtensionObject, EXTENSIONOBJECT) +UA_ENCODING_HELPERS(DataValue, DATAVALUE) +UA_ENCODING_HELPERS(Variant, VARIANT) +UA_ENCODING_HELPERS(DiagnosticInfo, DIAGNOSTICINFO) + +_UA_END_DECLS + + +/**** amalgamated original file "/build_freeRTOS/src_generated/open62541/transport_generated.h" ****/ + +/********************************** + * Autogenerated -- do not modify * + **********************************/ + + +#ifdef UA_ENABLE_AMALGAMATION +#else + +#endif + + + +_UA_BEGIN_DECLS + + +/** + * 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 8 +extern UA_EXPORT const UA_DataType UA_TRANSPORT[UA_TRANSPORT_COUNT]; + +/** + * 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_INVALID = 0x0, + __UA_MESSAGETYPE_FORCE32BIT = 0x7fffffff +} UA_MessageType; +UA_STATIC_ASSERT(sizeof(UA_MessageType) == sizeof(UA_Int32), enum_must_be_32bit); + +#define UA_TRANSPORT_MESSAGETYPE 0 + +/** + * 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 1 + +/** + * TcpMessageHeader + * ^^^^^^^^^^^^^^^^ + * TCP Header */ +typedef struct { + UA_UInt32 messageTypeAndChunkType; + UA_UInt32 messageSize; +} UA_TcpMessageHeader; + +#define UA_TRANSPORT_TCPMESSAGEHEADER 2 + +/** + * 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 3 + +/** + * 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 4 + +/** + * TcpErrorMessage + * ^^^^^^^^^^^^^^^ + * Error Message */ +typedef struct { + UA_UInt32 error; + UA_String reason; +} UA_TcpErrorMessage; + +#define UA_TRANSPORT_TCPERRORMESSAGE 5 + +/** + * AsymmetricAlgorithmSecurityHeader + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Asymmetric Security Header */ +typedef struct { + UA_ByteString securityPolicyUri; + UA_ByteString senderCertificate; + UA_ByteString receiverCertificateThumbprint; +} UA_AsymmetricAlgorithmSecurityHeader; + +#define UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER 6 + +/** + * SequenceHeader + * ^^^^^^^^^^^^^^ + * Secure Layer Sequence Header */ +typedef struct { + UA_UInt32 sequenceNumber; + UA_UInt32 requestId; +} UA_SequenceHeader; + +#define UA_TRANSPORT_SEQUENCEHEADER 7 + + +_UA_END_DECLS + + +/**** amalgamated original file "/build_freeRTOS/src_generated/open62541/transport_generated_handling.h" ****/ + +/********************************** + * Autogenerated -- do not modify * + **********************************/ + + + +_UA_BEGIN_DECLS + +#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 + + +/* 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) { + return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]); +} + +UA_DEPRECATED static UA_INLINE void +UA_MessageType_deleteMembers(UA_MessageType *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]); +} + +static UA_INLINE void +UA_MessageType_clear(UA_MessageType *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]); +} + +static UA_INLINE void +UA_MessageType_delete(UA_MessageType *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]); +} + +/* 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) { + return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]); +} + +UA_DEPRECATED static UA_INLINE void +UA_ChunkType_deleteMembers(UA_ChunkType *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]); +} + +static UA_INLINE void +UA_ChunkType_clear(UA_ChunkType *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]); +} + +static UA_INLINE void +UA_ChunkType_delete(UA_ChunkType *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]); +} + +/* 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) { + return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]); +} + +UA_DEPRECATED static UA_INLINE void +UA_TcpMessageHeader_deleteMembers(UA_TcpMessageHeader *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]); +} + +static UA_INLINE void +UA_TcpMessageHeader_clear(UA_TcpMessageHeader *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]); +} + +static UA_INLINE void +UA_TcpMessageHeader_delete(UA_TcpMessageHeader *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]); +} + +/* 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]); +} + +UA_DEPRECATED static UA_INLINE void +UA_TcpHelloMessage_deleteMembers(UA_TcpHelloMessage *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]); +} + +static UA_INLINE void +UA_TcpHelloMessage_clear(UA_TcpHelloMessage *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]); +} + +static UA_INLINE void +UA_TcpHelloMessage_delete(UA_TcpHelloMessage *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]); +} + +/* 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) { + return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]); +} + +UA_DEPRECATED static UA_INLINE void +UA_TcpAcknowledgeMessage_deleteMembers(UA_TcpAcknowledgeMessage *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]); +} + +static UA_INLINE void +UA_TcpAcknowledgeMessage_clear(UA_TcpAcknowledgeMessage *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]); +} + +static UA_INLINE void +UA_TcpAcknowledgeMessage_delete(UA_TcpAcknowledgeMessage *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]); +} + +/* 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]); +} + +UA_DEPRECATED static UA_INLINE void +UA_TcpErrorMessage_deleteMembers(UA_TcpErrorMessage *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]); +} + +static UA_INLINE void +UA_TcpErrorMessage_clear(UA_TcpErrorMessage *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]); +} + +static UA_INLINE void +UA_TcpErrorMessage_delete(UA_TcpErrorMessage *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]); +} + +/* 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]); +} + +UA_DEPRECATED static UA_INLINE void +UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(UA_AsymmetricAlgorithmSecurityHeader *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); +} + +static UA_INLINE void +UA_AsymmetricAlgorithmSecurityHeader_clear(UA_AsymmetricAlgorithmSecurityHeader *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); +} + +static UA_INLINE void +UA_AsymmetricAlgorithmSecurityHeader_delete(UA_AsymmetricAlgorithmSecurityHeader *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]); +} + +/* 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) { + return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]); +} + +UA_DEPRECATED static UA_INLINE void +UA_SequenceHeader_deleteMembers(UA_SequenceHeader *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]); +} + +static UA_INLINE void +UA_SequenceHeader_clear(UA_SequenceHeader *p) { + UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]); +} + +static UA_INLINE void +UA_SequenceHeader_delete(UA_SequenceHeader *p) { + UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]); +} + +#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 +# pragma GCC diagnostic pop +#endif + +_UA_END_DECLS + + +/**** amalgamated original file "/src/ua_connection_internal.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Florian Palm + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + + +_UA_BEGIN_DECLS + +/* 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); + +_UA_END_DECLS + + +/**** amalgamated original file "/src/ua_securechannel.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Florian Palm + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB + */ + + + + +_UA_BEGIN_DECLS + +/* The message header of the OPC UA binary protocol is structured as follows: + * + * - MessageType (3 Byte) + * - IsFinal (1 Byte) + * - MessageSize (4 Byte) + * *** UA_SECURECHANNEL_MESSAGEHEADER_LENGTH *** + * - SecureChannelId (4 Byte) + * *** UA_SECURECHANNEL_CHANNELHEADER_LENGTH *** + * - SecurityHeader (4 Byte TokenId for symmetric, otherwise dynamic length) + * - SequenceHeader (8 Byte) + * - SequenceNumber + * - RequestId + */ + +#define UA_SECURECHANNEL_MESSAGEHEADER_LENGTH 8 +#define UA_SECURECHANNEL_CHANNELHEADER_LENGTH 12 +#define UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH 4 +#define UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH 8 +#define UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH \ + (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + \ + UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH) +#define UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH \ + (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + \ + UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH + \ + UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH) + +/* Minimum length of a valid message (ERR message with an empty reason) */ +#define UA_SECURECHANNEL_MESSAGE_MIN_LENGTH 16 + +/* Thread-local variables to force failure modes during testing */ +#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS +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 { + SLIST_ENTRY(UA_SessionHeader) next; + UA_NodeId authenticationToken; + UA_SecureChannel *channel; /* The pointer back to the SecureChannel in the session. */ +} UA_SessionHeader; + +/* For chunked requests */ +typedef struct UA_Chunk { + SIMPLEQ_ENTRY(UA_Chunk) pointers; + UA_ByteString bytes; + UA_MessageType messageType; + UA_ChunkType chunkType; + UA_UInt32 requestId; + UA_Boolean copied; /* Do the bytes point to a buffer from the network or was + * memory allocated for the chunk separately */ +} UA_Chunk; + +typedef SIMPLEQ_HEAD(UA_ChunkQueue, UA_Chunk) UA_ChunkQueue; + +typedef enum { + UA_SECURECHANNELRENEWSTATE_NORMAL, + + /* Client has sent an OPN, but not received a response so far. */ + UA_SECURECHANNELRENEWSTATE_SENT, + + /* The server waits for the first request with the new token for the rollover. + * The new token is stored in the altSecurityToken. The configured local and + * remote symmetric encryption keys are the old ones. */ + UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER, + + /* The client already uses the new token. But he waits for the server to respond + * with the new token to complete the rollover. The old token is stored in + * altSecurityToken. The local symmetric encryption key is new. The remote + * encryption key is the old one. */ + UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT +} UA_SecureChannelRenewState; + +struct UA_SecureChannel { + UA_SecureChannelState state; + UA_SecureChannelRenewState renewState; + UA_MessageSecurityMode securityMode; + UA_ConnectionConfig config; + + /* Rules for revolving the token with a renew OPN request: The client is + * allowed to accept messages with the old token until the OPN response has + * arrived. The server accepts the old token until one message secured with + * the new token has arrived. + * + * We recognize whether nextSecurityToken contains a valid next token if the + * ChannelId is not 0. */ + UA_ChannelSecurityToken securityToken; /* Also contains the channelId */ + UA_ChannelSecurityToken altSecurityToken; /* Alternative token for the rollover. + * See the renewState. */ + + /* 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 nonces. These are used to generate the key material + * and must not be reused once the keys are in place. + * + * Nonces are also used during the CreateSession / ActivateSession + * handshake. These are not handled here, as the Session handling can + * overlap with a RenewSecureChannel. */ + UA_ByteString remoteNonce; + UA_ByteString localNonce; + + UA_UInt32 receiveSequenceNumber; + UA_UInt32 sendSequenceNumber; + + /* Sessions that are bound to the SecureChannel */ + SLIST_HEAD(, UA_SessionHeader) sessions; + + /* If a buffer is received, first all chunks are put into the completeChunks + * queue. Then they are processed in order. This ensures that processing + * buffers is reentrant with the correct processing order. (This has lead to + * problems in the client in the past.) */ + UA_ChunkQueue completeChunks; /* Received full chunks that have not been + * decrypted so far */ + UA_ChunkQueue decryptedChunks; /* Received chunks that were decrypted but + * not processed */ + size_t decryptedChunksCount; + size_t decryptedChunksLength; + UA_ByteString incompleteChunk; /* A half-received chunk (TCP is a + * streaming protocol) is stored here */ + + UA_CertificateVerification *certificateVerification; + UA_StatusCode (*processOPNHeader)(void *application, UA_SecureChannel *channel, + const UA_AsymmetricAlgorithmSecurityHeader *asymHeader); +}; + +void UA_SecureChannel_init(UA_SecureChannel *channel, + const UA_ConnectionConfig *config); + +void UA_SecureChannel_close(UA_SecureChannel *channel); + +/* Process the remote configuration in the HEL/ACK handshake. The connection + * config is initialized with the local settings. */ +UA_StatusCode +UA_SecureChannel_processHELACK(UA_SecureChannel *channel, + const UA_TcpAcknowledgeMessage *remoteConfig); + +UA_StatusCode +UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel, + const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate); + +/* Remove (partially) received unprocessed chunks */ +void +UA_SecureChannel_deleteBuffered(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_StatusCode +UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *channel); + +UA_StatusCode +generateRemoteKeys(const 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); + +/** + * Receive Message + * --------------- */ + +typedef UA_StatusCode +(UA_ProcessMessageCallback)(void *application, UA_SecureChannel *channel, + UA_MessageType messageType, UA_UInt32 requestId, + UA_ByteString *message); + +/* Process a received buffer. The callback function is called with the message + * body if the message is complete. The message is removed afterwards. Returns + * if an irrecoverable error occured. + * + * Note that only MSG and CLO messages are decrypted. HEL/ACK/OPN/... are + * forwarded verbatim to the application. */ +UA_StatusCode +UA_SecureChannel_processBuffer(UA_SecureChannel *channel, void *application, + UA_ProcessMessageCallback callback, + const UA_ByteString *buffer); + +/* Try to receive at least one complete chunk on the connection. This blocks the + * current thread up to the given timeout. It will return once the first buffer + * has been received (and possibly processed when the message is complete). + * + * @param channel The SecureChannel + * @param application The client or server application + * @param callback The function pointer for processing complete messages + * @param timeout The timeout (in milliseconds) the method will block at most. + * @return Returns UA_STATUSCODE_GOOD or an error code. A timeout does not + * create an error. */ +UA_StatusCode +UA_SecureChannel_receive(UA_SecureChannel *channel, void *application, + UA_ProcessMessageCallback callback, UA_UInt32 timeout); + +/* Internal methods in ua_securechannel_crypto.h */ + +void +hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start, + const UA_Byte **buf_end); + +/* Decrypt and verify via the signature. The chunk buffer is reused to hold the + * decrypted data after the MessageHeader and SecurityHeader. The chunk length + * is reduced by the signature, padding and encryption overhead. + * + * The offset argument points to the start of the encrypted content (beginning + * with the SequenceHeader).*/ +UA_StatusCode +decryptAndVerifyChunk(const UA_SecureChannel *channel, + const UA_SecurityPolicyCryptoModule *cryptoModule, + UA_MessageType messageType, UA_ByteString *chunk, + size_t offset); + +size_t +calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel); + +UA_StatusCode +prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos, + const UA_Byte *buf_end, size_t totalLength, + size_t securityHeaderLength, UA_UInt32 requestId, + size_t *const finalLength); + +void +setBufPos(UA_MessageContext *mc); + +UA_StatusCode +checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId); + +UA_StatusCode +checkAsymHeader(UA_SecureChannel *channel, + const UA_AsymmetricAlgorithmSecurityHeader *asymHeader); + +void +padChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cm, + const UA_Byte *start, UA_Byte **pos); + +UA_StatusCode +signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength, + UA_ByteString *buf, size_t securityHeaderLength, + size_t totalLength); + +UA_StatusCode +signAndEncryptSym(UA_MessageContext *messageContext, + size_t preSigLength, size_t totalLength); + +/** + * 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 %" PRIu32 " | " MSG "%.0s", \ + ((CHANNEL)->connection ? (int)((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 %" PRIu32 " | " MSG "%.0s", \ + ((CHANNEL)->connection ? (int)((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 %" PRIu32 " | " MSG "%.0s", \ + ((CHANNEL)->connection ? (int)((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 %" PRIu32 " | " MSG "%.0s", \ + ((CHANNEL)->connection ? (int)((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 %" PRIu32 " | " MSG "%.0s", \ + ((CHANNEL)->connection ? (int)((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 %" PRIu32 " | " 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__, "")) + +_UA_END_DECLS + + +/**** amalgamated original file "/src/ua_timer.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2017, 2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + + +_UA_BEGIN_DECLS + +/* The timer is protected by its own mutex. The mutex is released before calling + * into the callbacks. So the timer can be modified from the callbacks it is + * executing. Also, the timer mutex can never lead to locking. Because the timer + * mutex will be left without acquiring another mutex. + * + * Obviously, the timer must not be deleted from within one of its + * callbacks. */ + +/* Callback where the application is either a client or a server */ +typedef void (*UA_ApplicationCallback)(void *application, void *data); + +typedef struct UA_TimerEntry { + struct aa_entry treeEntry; + UA_TimerPolicy timerPolicy; /* Timer policy to handle cycle misses */ + UA_DateTime nextTime; /* The next time when the callback + * is to be executed */ + UA_UInt64 interval; /* Interval in 100ns resolution. If + the interval is zero, the + callback is not repeated and + removed after execution. */ + UA_ApplicationCallback callback; + void *application; + void *data; + + struct aa_entry idTreeEntry; + UA_UInt64 id; /* Id of the entry */ +} UA_TimerEntry; + +typedef struct { + struct aa_head root; /* The root of the time-sorted tree */ + struct aa_head idRoot; /* The root of the id-sorted tree */ + UA_UInt64 idCounter; /* Generate unique identifiers. Identifiers are + * always above zero. */ +#if UA_MULTITHREADING >= 100 + UA_Lock timerMutex; +#endif +} UA_Timer; + +void +UA_Timer_init(UA_Timer *t); + +UA_StatusCode +UA_Timer_addTimedCallback(UA_Timer *t, UA_ApplicationCallback callback, + void *application, void *data, UA_DateTime date, + UA_UInt64 *callbackId); + +/* Add a pre-allocated and pre-filled UA_TimerEntry. This cannot fail. It is + * used, for example, for delayed memory reclamation where the data structure + * begins with a UA_TimerEntry. */ +void +UA_Timer_addTimerEntry(UA_Timer *t, UA_TimerEntry *te, UA_UInt64 *callbackId); + +UA_StatusCode +UA_Timer_addRepeatedCallback(UA_Timer *t, UA_ApplicationCallback callback, + void *application, void *data, UA_Double interval_ms, + UA_DateTime *baseTime, UA_TimerPolicy timerPolicy, + UA_UInt64 *callbackId); + +UA_StatusCode +UA_Timer_changeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId, + UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy); + +void +UA_Timer_removeCallback(UA_Timer *t, UA_UInt64 callbackId); + +/* 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_TimerExecutionCallback)(void *executionApplication, UA_ApplicationCallback cb, + void *callbackApplication, void *data); + +UA_DateTime +UA_Timer_process(UA_Timer *t, UA_DateTime nowMonotonic, + UA_TimerExecutionCallback executionCallback, + void *executionApplication); + +void +UA_Timer_clear(UA_Timer *t); + +_UA_END_DECLS + + +/**** amalgamated original file "/src/server/ua_session.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green) + */ + + + + +_UA_BEGIN_DECLS + +#define UA_MAXCONTINUATIONPOINTS 5 + +struct ContinuationPoint; +typedef struct ContinuationPoint ContinuationPoint; + +/* Returns the next entry in the linked list */ +ContinuationPoint * +ContinuationPoint_clear(ContinuationPoint *cp); + +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; /* in ms */ + UA_DateTime validTill; + UA_ByteString serverNonce; + + UA_UInt16 availableContinuationPoints; + ContinuationPoint *continuationPoints; + + size_t paramsSize; + UA_KeyValuePair *params; + +#ifdef UA_ENABLE_SUBSCRIPTIONS + size_t subscriptionsSize; + TAILQ_HEAD(, UA_Subscription) subscriptions; /* Late subscriptions that do eventually + * publish are moved to the tail. So that + * other late subscriptions are not + * starved. */ + SIMPLEQ_HEAD(, UA_PublishResponseEntry) responseQueue; + 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_clear(UA_Session *session, UA_Server *server); +void UA_Session_attachToSecureChannel(UA_Session *session, UA_SecureChannel *channel); +void UA_Session_detachFromSecureChannel(UA_Session *session); +UA_StatusCode UA_Session_generateNonce(UA_Session *session); + +/* 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_attachSubscription(UA_Session *session, UA_Subscription *sub); + +void +UA_Session_detachSubscription(UA_Server *server, UA_Session *session, + UA_Subscription *sub); + +UA_Subscription * +UA_Session_getSubscriptionById(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_SESSION_INTERNAL(LOGGER, LEVEL, SESSION, MSG, ...) \ + do { \ + UA_String idString = UA_STRING_NULL; \ + UA_UInt32 channelId = 0; \ + if(SESSION) { \ + UA_NodeId_print(&(SESSION)->sessionId, &idString); \ + channelId = (SESSION)->header.channel ? \ + (SESSION)->header.channel->securityToken.channelId : 0; \ + } \ + UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SESSION, \ + "SecureChannel %" PRIu32 " | Session %.*s | " MSG "%.0s", \ + channelId, (int)idString.length, idString.data, __VA_ARGS__); \ + UA_String_clear(&idString); \ + } while(0) + +#if UA_LOGLEVEL <= 100 +# define UA_LOG_TRACE_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, TRACE, SESSION, __VA_ARGS__, "")) +#else +# define UA_LOG_TRACE_SESSION(LOGGER, SESSION, ...) +#endif + +#if UA_LOGLEVEL <= 200 +# define UA_LOG_DEBUG_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, DEBUG, SESSION, __VA_ARGS__, "")) +#else +# define UA_LOG_DEBUG_SESSION(LOGGER, SESSION, ...) +#endif + +#if UA_LOGLEVEL <= 300 +# define UA_LOG_INFO_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, INFO, SESSION, __VA_ARGS__, "")) +#else +# define UA_LOG_INFO_SESSION(LOGGER, SESSION, ...) +#endif + +#if UA_LOGLEVEL <= 400 +# define UA_LOG_WARNING_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, WARNING, SESSION, __VA_ARGS__, "")) +#else +# define UA_LOG_WARNING_SESSION(LOGGER, SESSION, ...) +#endif + +#if UA_LOGLEVEL <= 500 +# define UA_LOG_ERROR_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, ERROR, SESSION, __VA_ARGS__, "")) +#else +# define UA_LOG_ERROR_SESSION(LOGGER, SESSION, ...) +#endif + +#if UA_LOGLEVEL <= 600 +# define UA_LOG_FATAL_SESSION(LOGGER, SESSION, ...) \ + UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, FATAL, SESSION, __VA_ARGS__, "")) +#else +# define UA_LOG_FATAL_SESSION(LOGGER, SESSION, ...) +#endif + +_UA_END_DECLS + + +/**** amalgamated original file "/src/server/ua_subscription.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2015-2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + * Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green) + * Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) + * Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner) + */ + + + + +_UA_BEGIN_DECLS + +#ifdef UA_ENABLE_SUBSCRIPTIONS + +/* 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. */ + +/*****************/ +/* Notifications */ +/*****************/ + +/* Set to the TAILQ_NEXT pointer of a notification, the sentinel that the + * notification was not added to the global queue */ +#define UA_SUBSCRIPTION_QUEUE_SENTINEL ((UA_Notification*)0x01) + +typedef struct UA_Notification { + TAILQ_ENTRY(UA_Notification) localEntry; /* Notification list for the MonitoredItem */ + TAILQ_ENTRY(UA_Notification) globalEntry; /* Notification list for the Subscription */ + UA_MonitoredItem *mon; /* Always set */ + + /* The event field is used if mon->attributeId is the EventNotifier */ + union { + UA_MonitoredItemNotification dataChange; +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + UA_EventFieldList event; +#endif + } data; + +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS + UA_Boolean isOverflowEvent; /* Counted manually */ + UA_EventFilterResult result; +#endif +} UA_Notification; + +/* Initializes and sets the sentinel pointers */ +UA_Notification * UA_Notification_new(void); + +/* Notifications are always added to the queue of the MonitoredItem. That queue + * can overflow. If Notifications are reported, they are also added to the + * global queue of the Subscription. There they are picked up by the publishing + * callback. + * + * There are two ways Notifications can be put into the global queue of the + * Subscription: They are added because the MonitoringMode of the MonitoredItem + * is "reporting". Or the MonitoringMode is "sampling" and a link is trigered + * that puts the last Notification into the global queue. */ +void UA_Notification_enqueueAndTrigger(UA_Server *server, + UA_Notification *n); + +/* Dequeue and delete the notification */ +void UA_Notification_delete(UA_Notification *n); + +/* A NotificationMessage contains an array of notifications. + * Sent NotificationMessages are stored for the republish service. */ +typedef struct UA_NotificationMessageEntry { + TAILQ_ENTRY(UA_NotificationMessageEntry) listEntry; + UA_NotificationMessage message; +} UA_NotificationMessageEntry; + +/* Queue Definitions */ +typedef TAILQ_HEAD(NotificationQueue, UA_Notification) NotificationQueue; +typedef TAILQ_HEAD(NotificationMessageQueue, UA_NotificationMessageEntry) + NotificationMessageQueue; + +/*****************/ +/* MonitoredItem */ +/*****************/ + +struct UA_MonitoredItem { + UA_TimerEntry delayedFreePointers; + LIST_ENTRY(UA_MonitoredItem) listEntry; /* Linked list in the Subscription */ + UA_MonitoredItem *next; /* Linked list of MonitoredItems directly attached + * to a Node. Initialized to ~0 to indicate that the + * MonitoredItem is not added to a node. */ + UA_Subscription *subscription; /* If NULL, then this is a Local MonitoredItem */ + UA_UInt32 monitoredItemId; + + /* Status and Settings */ + UA_ReadValueId itemToMonitor; + UA_MonitoringMode monitoringMode; + UA_TimestampsToReturn timestampsToReturn; + UA_Boolean sampleCallbackIsRegistered; + UA_Boolean registered; /* Registered in the server / Subscription */ + UA_DateTime triggeredUntil; /* If the MonitoringMode is SAMPLING, a + * triggered MonitoredItem puts the next + * Notification into the global queue (of the + * Subscription) for publishing. But triggering + * is only active for the duration of one + * publishin cycle. */ + + /* If the filter is a UA_DataChangeFilter: The DataChangeFilter always + * contains an absolute deadband definition. Part 8, §6.2 gives the + * following formula to test for percentage deadbands: + * + * DataChange if (absolute value of (last cached value - current value) + * > (deadbandValue/100.0) * ((high–low) of EURange))) + * + * So we can convert from a percentage to an absolute deadband and keep + * the hot code path simple. + * + * TODO: Store the percentage deadband to recompute when the UARange is + * changed at runtime of the MonitoredItem */ + UA_MonitoringParameters parameters; + + /* Sampling Callback */ + UA_UInt64 sampleCallbackId; + UA_DataValue lastValue; + + /* Triggering Links */ + size_t triggeringLinksSize; + UA_UInt32 *triggeringLinks; + + /* Notification Queue */ + NotificationQueue queue; + size_t queueSize; /* This is the current size. See also the configured + * (maximum) queueSize in the parameters. */ + size_t eventOverflows; /* Separate counter for the queue. Can at most double + * the queue size */ +}; + +void UA_MonitoredItem_init(UA_MonitoredItem *mon); + +void +UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *monitoredItem); + +void +UA_MonitoredItem_removeOverflowInfoBits(UA_MonitoredItem *mon); + +void +UA_Server_registerMonitoredItem(UA_Server *server, UA_MonitoredItem *mon); + +/* Register sampling. Either by adding a repeated callback or by adding the + * MonitoredItem to a linked list in the node. */ +UA_StatusCode +UA_MonitoredItem_registerSampling(UA_Server *server, UA_MonitoredItem *mon); + +void +UA_MonitoredItem_unregisterSampling(UA_Server *server, + UA_MonitoredItem *mon); + +UA_StatusCode +UA_MonitoredItem_setMonitoringMode(UA_Server *server, UA_MonitoredItem *mon, + UA_MonitoringMode monitoringMode); + +void +UA_MonitoredItem_sampleCallback(UA_Server *server, + UA_MonitoredItem *monitoredItem); + +UA_StatusCode +sampleCallbackWithValue(UA_Server *server, UA_Subscription *sub, + UA_MonitoredItem *mon, UA_DataValue *value); + +UA_StatusCode +UA_MonitoredItem_removeLink(UA_Subscription *sub, UA_MonitoredItem *mon, + UA_UInt32 linkId); + +UA_StatusCode +UA_MonitoredItem_addLink(UA_Subscription *sub, UA_MonitoredItem *mon, + UA_UInt32 linkId); + +UA_StatusCode +UA_MonitoredItem_createDataChangeNotification(UA_Server *server, + UA_Subscription *sub, + UA_MonitoredItem *mon, + const UA_DataValue *value); + +UA_StatusCode +UA_Event_addEventToMonitoredItem(UA_Server *server, const UA_NodeId *event, + UA_MonitoredItem *mon); + +UA_StatusCode +UA_Event_generateEventId(UA_ByteString *generatedId); + +void +UA_Event_staticSelectClauseValidation(UA_Server *server, + const UA_EventFilter *eventFilter, + UA_StatusCode *result); + +UA_StatusCode +UA_Event_staticWhereClauseValidation(UA_Server *server, + const UA_ContentFilter *filter, + UA_ContentFilterResult *); + +/* Remove entries until mon->maxQueueSize is reached. Sets infobits for lost + * data if required. */ +void +UA_MonitoredItem_ensureQueueSpace(UA_Server *server, UA_MonitoredItem *mon); + +/****************/ +/* Subscription */ +/****************/ + +/* 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; + +/* Subscriptions are managed in a server-wide linked list. If they are attached + * to a Session, then they are additionaly in the per-Session linked-list. A + * subscription is always generated for a Session. But the CloseSession Service + * may keep Subscriptions intact beyond the Session lifetime. They can then be + * re-bound to a new Session with the TransferSubscription Service. */ +struct UA_Subscription { + UA_TimerEntry delayedFreePointers; + LIST_ENTRY(UA_Subscription) serverListEntry; + TAILQ_ENTRY(UA_Subscription) sessionListEntry; /* Only set if session != NULL */ + UA_Session *session; /* May be NULL if no session is attached. */ + 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_StatusCode statusChange; /* If set, a notification is generated and the + * Subscription is deleted within + * UA_Subscription_publish. */ + UA_UInt32 nextSequenceNumber; + UA_UInt32 currentKeepAliveCount; + UA_UInt32 currentLifetimeCount; + + /* Publish Callback. Registered if id > 0. */ + UA_UInt64 publishCallbackId; + + /* MonitoredItems */ + UA_UInt32 lastMonitoredItemId; /* increase the identifiers */ + LIST_HEAD(, UA_MonitoredItem) monitoredItems; + UA_UInt32 monitoredItemsSize; + + /* Global list of notifications from the MonitoredItems */ + TAILQ_HEAD(, UA_Notification) notificationQueue; + UA_UInt32 notificationQueueSize; /* Total queue size */ + UA_UInt32 dataChangeNotifications; + UA_UInt32 eventNotifications; + + /* Notifications to be sent out now (already late). In a regular publish + * callback, all queued notifications are sent out. In a late publish + * response, only the notifications left from the last regular publish + * callback are sent. */ + UA_UInt32 readyNotifications; + + /* Retransmission Queue */ + NotificationMessageQueue retransmissionQueue; + size_t retransmissionQueueSize; +}; + +UA_Subscription * UA_Subscription_new(void); + +void +UA_Subscription_delete(UA_Server *server, UA_Subscription *sub); + +UA_StatusCode +Subscription_registerPublishCallback(UA_Server *server, + UA_Subscription *sub); + +void +Subscription_unregisterPublishCallback(UA_Server *server, + UA_Subscription *sub); + +UA_MonitoredItem * +UA_Subscription_getMonitoredItem(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); + +UA_Boolean +UA_Session_reachedPublishReqLimit(UA_Server *server, UA_Session *session); + +/* Forward declaration for A&C used in ua_server_internal.h" */ +struct UA_ConditionSource; +typedef struct UA_ConditionSource UA_ConditionSource; + +/***********/ +/* Helpers */ +/***********/ + +/* Evaluate content filter, Only for unit testing */ +#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS +UA_StatusCode +UA_Server_evaluateWhereClauseContentFilter(UA_Server *server, UA_Session *session, + const UA_NodeId *eventNode, + const UA_ContentFilter *contentFilter, + UA_ContentFilterResult *contentFilterResult); +#endif + +/* Setting an integer value within bounds */ +#define UA_BOUNDEDVALUE_SETWBOUNDS(BOUNDS, SRC, DST) { \ + if(SRC > BOUNDS.max) DST = BOUNDS.max; \ + else if(SRC < BOUNDS.min) DST = BOUNDS.min; \ + else DST = SRC; \ + } + +/* Logging + * See a description of the tricks used in ua_session.h */ +#define UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, LEVEL, SUB, MSG, ...) do { \ + UA_String idString = UA_STRING_NULL; \ + if((SUB) && (SUB)->session) { \ + UA_NodeId_print(&(SUB)->session->sessionId, &idString); \ + UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SESSION, \ + "SecureChannel %" PRIu32 " | Session %.*s | Subscription %" PRIu32 " | " MSG "%.0s", \ + ((SUB)->session->header.channel ? \ + (SUB)->session->header.channel->securityToken.channelId : 0), \ + (int)idString.length, idString.data, (SUB)->subscriptionId, __VA_ARGS__); \ + UA_String_clear(&idString); \ + } else { \ + UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SERVER, \ + "Subscription %" PRIu32 " | " MSG "%.0s", \ + (SUB) ? (SUB)->subscriptionId : 0, __VA_ARGS__); \ + } \ +} while(0) + +#if UA_LOGLEVEL <= 100 +# define UA_LOG_TRACE_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, TRACE, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_TRACE_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 200 +# define UA_LOG_DEBUG_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, DEBUG, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_DEBUG_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 300 +# define UA_LOG_INFO_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, INFO, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_INFO_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 400 +# define UA_LOG_WARNING_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, WARNING, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_WARNING_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 500 +# define UA_LOG_ERROR_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, ERROR, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_ERROR_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#if UA_LOGLEVEL <= 600 +# define UA_LOG_FATAL_SUBSCRIPTION(LOGGER, SUB, ...) \ + UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, FATAL, SUB, __VA_ARGS__, "")) +#else +# define UA_LOG_FATAL_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0) +#endif + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +_UA_END_DECLS + + +/**** amalgamated original file "/src/pubsub/ua_pubsub_networkmessage.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2017 - 2018 Fraunhofer IOSB (Author: Tino Bischoff) + * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner) + */ + + + +_UA_BEGIN_DECLS + +/* DataSet Payload Header */ +typedef struct { + UA_Byte count; + UA_UInt16* dataSetWriterIds; +} UA_DataSetPayloadHeader; + +/* FieldEncoding Enum */ +typedef enum { + UA_FIELDENCODING_VARIANT = 0, + UA_FIELDENCODING_RAWDATA = 1, + UA_FIELDENCODING_DATAVALUE = 2, + UA_FIELDENCODING_UNKNOWN = 3 +} UA_FieldEncoding; + +/* DataSetMessage Type */ +typedef enum { + UA_DATASETMESSAGE_DATAKEYFRAME = 0, + UA_DATASETMESSAGE_DATADELTAFRAME = 1, + UA_DATASETMESSAGE_EVENT = 2, + UA_DATASETMESSAGE_KEEPALIVE = 3 +} UA_DataSetMessageType; + +/* DataSetMessage Header */ +typedef struct { + UA_Boolean dataSetMessageValid; + UA_FieldEncoding fieldEncoding; + UA_Boolean dataSetMessageSequenceNrEnabled; + UA_Boolean timestampEnabled; + UA_Boolean statusEnabled; + UA_Boolean configVersionMajorVersionEnabled; + UA_Boolean configVersionMinorVersionEnabled; + UA_DataSetMessageType dataSetMessageType; + UA_Boolean picoSecondsIncluded; + UA_UInt16 dataSetMessageSequenceNr; + UA_UtcTime timestamp; + UA_UInt16 picoSeconds; + UA_UInt16 status; + UA_UInt32 configVersionMajorVersion; + UA_UInt32 configVersionMinorVersion; +} UA_DataSetMessageHeader; + +/** + * DataSetMessage + * ^^^^^^^^^^^^^^ */ + +typedef struct { + UA_UInt16 fieldCount; + UA_DataValue* dataSetFields; + UA_ByteString rawFields; + /* Json keys for the dataSetFields: TODO: own dataSetMessageType for json? */ + UA_String* fieldNames; +} UA_DataSetMessage_DataKeyFrameData; + +typedef struct { + UA_UInt16 fieldIndex; + UA_DataValue fieldValue; +} UA_DataSetMessage_DeltaFrameField; + +typedef struct { + UA_UInt16 fieldCount; + UA_DataSetMessage_DeltaFrameField* deltaFrameFields; +} UA_DataSetMessage_DataDeltaFrameData; + +typedef struct { + UA_DataSetMessageHeader header; + union { + UA_DataSetMessage_DataKeyFrameData keyFrameData; + UA_DataSetMessage_DataDeltaFrameData deltaFrameData; + } data; +} UA_DataSetMessage; + +typedef struct { + UA_UInt16* sizes; + UA_DataSetMessage* dataSetMessages; +} UA_DataSetPayload; + +typedef enum { + UA_PUBLISHERDATATYPE_BYTE = 0, + UA_PUBLISHERDATATYPE_UINT16 = 1, + UA_PUBLISHERDATATYPE_UINT32 = 2, + UA_PUBLISHERDATATYPE_UINT64 = 3, + UA_PUBLISHERDATATYPE_STRING = 4 +} UA_PublisherIdDatatype; + +typedef enum { + UA_NETWORKMESSAGE_DATASET = 0, + UA_NETWORKMESSAGE_DISCOVERY_REQUEST = 1, + UA_NETWORKMESSAGE_DISCOVERY_RESPONSE = 2 +} UA_NetworkMessageType; + +/** + * UA_NetworkMessageGroupHeader + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ +typedef struct { + UA_Boolean writerGroupIdEnabled; + UA_Boolean groupVersionEnabled; + UA_Boolean networkMessageNumberEnabled; + UA_Boolean sequenceNumberEnabled; + UA_UInt16 writerGroupId; + UA_UInt32 groupVersion; // spec: type "VersionTime" + UA_UInt16 networkMessageNumber; + UA_UInt16 sequenceNumber; +} UA_NetworkMessageGroupHeader; + +/** + * UA_NetworkMessageSecurityHeader + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ +typedef struct { + UA_Boolean networkMessageSigned; + UA_Boolean networkMessageEncrypted; + UA_Boolean securityFooterEnabled; + UA_Boolean forceKeyReset; + UA_UInt32 securityTokenId; // spec: IntegerId + UA_ByteString messageNonce; + UA_UInt16 securityFooterSize; +} UA_NetworkMessageSecurityHeader; + +/** + * UA_NetworkMessage + * ^^^^^^^^^^^^^^^^^ */ +typedef struct { + UA_Byte version; + UA_Boolean messageIdEnabled; + UA_String messageId; /* For Json NetworkMessage */ + UA_Boolean publisherIdEnabled; + UA_Boolean groupHeaderEnabled; + UA_Boolean payloadHeaderEnabled; + UA_PublisherIdDatatype publisherIdType; + UA_Boolean dataSetClassIdEnabled; + UA_Boolean securityEnabled; + UA_Boolean timestampEnabled; + UA_Boolean picosecondsEnabled; + UA_Boolean chunkMessage; + UA_Boolean promotedFieldsEnabled; + UA_NetworkMessageType networkMessageType; + union { + UA_Byte publisherIdByte; + UA_UInt16 publisherIdUInt16; + UA_UInt32 publisherIdUInt32; + UA_UInt64 publisherIdUInt64; + UA_Guid publisherIdGuid; + UA_String publisherIdString; + } publisherId; + UA_Guid dataSetClassId; + + UA_NetworkMessageGroupHeader groupHeader; + + union { + UA_DataSetPayloadHeader dataSetPayloadHeader; + } payloadHeader; + + UA_DateTime timestamp; + UA_UInt16 picoseconds; + UA_UInt16 promotedFieldsSize; + UA_Variant* promotedFields; /* BaseDataType */ + + UA_NetworkMessageSecurityHeader securityHeader; + + union { + UA_DataSetPayload dataSetPayload; + } payload; + + UA_ByteString securityFooter; +} UA_NetworkMessage; + +/**********************************************/ +/* Network Message Offsets */ +/**********************************************/ + +/* Offsets for buffered messages in the PubSub fast path. */ +typedef enum { + UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER, + UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER, + UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING, + UA_PUBSUB_OFFSETTYPE_TIMESTAMP_PICOSECONDS, + UA_PUBSUB_OFFSETTYPE_TIMESTAMP, /* source pointer */ + UA_PUBSUB_OFFSETTYPE_TIMESTAMP_NOW, /* no source */ + UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE, + UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT, + UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW, + /* For subscriber RT */ + UA_PUBSUB_OFFSETTYPE_PUBLISHERID, + UA_PUBSUB_OFFSETTYPE_WRITERGROUPID, + UA_PUBSUB_OFFSETTYPE_DATASETWRITERID + /* Add more offset types as needed */ +} UA_NetworkMessageOffsetType; + +typedef struct { + UA_NetworkMessageOffsetType contentType; + union { + struct { + UA_DataValue *value; + size_t valueBinarySize; + } value; + UA_DateTime *timestamp; + } offsetData; + size_t offset; +} UA_NetworkMessageOffset; + +typedef struct { + UA_ByteString buffer; /* The precomputed message buffer */ + UA_NetworkMessageOffset *offsets; /* Offsets for changes in the message buffer */ + size_t offsetsSize; + UA_Boolean RTsubscriberEnabled; /* Addtional offsets computation like publisherId, WGId if this bool enabled */ + UA_NetworkMessage *nm; /* The precomputed NetworkMessage for subscriber */ + size_t rawMessageLength; +} UA_NetworkMessageOffsetBuffer; + +/** + * DataSetMessage + * ^^^^^^^^^^^^^^ */ + +UA_StatusCode +UA_DataSetMessageHeader_encodeBinary(const UA_DataSetMessageHeader* src, + UA_Byte **bufPos, const UA_Byte *bufEnd); + +UA_StatusCode +UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_DataSetMessageHeader* dst); + +size_t +UA_DataSetMessageHeader_calcSizeBinary(const UA_DataSetMessageHeader* p); + +UA_StatusCode +UA_DataSetMessage_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd); + +UA_StatusCode +UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_DataSetMessage* dst, UA_UInt16 dsmSize); + +size_t +UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage *p, UA_NetworkMessageOffsetBuffer *offsetBuffer, + size_t currentOffset); + +void UA_DataSetMessage_clear(const UA_DataSetMessage* p); + +/** + * NetworkMessage + * ^^^^^^^^^^^^^^ */ + +UA_StatusCode +UA_NetworkMessage_updateBufferedMessage(UA_NetworkMessageOffsetBuffer *buffer); + +UA_StatusCode +UA_NetworkMessage_updateBufferedNwMessage(UA_NetworkMessageOffsetBuffer *buffer, + const UA_ByteString *src, size_t *bufferPosition); + + +/** + * NetworkMessage Encoding + * ^^^^^^^^^^^^^^^^^^^^^^^ */ + +/* If dataToEncryptStart not-NULL, then it will be set to the start-position of + * the payload in the buffer. */ +UA_StatusCode +UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, + UA_Byte **bufPos, const UA_Byte *bufEnd, + UA_Byte **dataToEncryptStart); + +UA_StatusCode +UA_NetworkMessage_encodeHeaders(const UA_NetworkMessage* src, + UA_Byte **bufPos, const UA_Byte *bufEnd); + +UA_StatusCode +UA_NetworkMessage_encodePayload(const UA_NetworkMessage* src, + UA_Byte **bufPos, const UA_Byte *bufEnd); + +UA_StatusCode +UA_NetworkMessage_encodeFooters(const UA_NetworkMessage* src, + UA_Byte **bufPos, const UA_Byte *bufEnd); + +/** + * NetworkMessage Decoding + * ^^^^^^^^^^^^^^^^^^^^^^^ */ + +UA_StatusCode +UA_NetworkMessage_decodeHeaders(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst); + +UA_StatusCode +UA_NetworkMessage_decodePayload(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst); + +UA_StatusCode +UA_NetworkMessage_decodeFooters(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst); + +UA_StatusCode +UA_NetworkMessage_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst); + + +UA_StatusCode +UA_NetworkMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst); + +size_t +UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, + UA_NetworkMessageOffsetBuffer *offsetBuffer); + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + +UA_StatusCode +UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm, UA_MessageSecurityMode securityMode, + UA_PubSubSecurityPolicy *policy, void *policyContext, + UA_Byte *messageStart, UA_Byte *encryptStart, + UA_Byte *sigStart); +#endif + +void +UA_NetworkMessage_clear(UA_NetworkMessage* p); + +void +UA_NetworkMessage_delete(UA_NetworkMessage* p); + + +#ifdef UA_ENABLE_JSON_ENCODING +UA_StatusCode +UA_NetworkMessage_encodeJson(const UA_NetworkMessage *src, + UA_Byte **bufPos, const UA_Byte **bufEnd, UA_String *namespaces, + size_t namespaceSize, UA_String *serverUris, + size_t serverUriSize, UA_Boolean useReversible); + +size_t +UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage *src, + UA_String *namespaces, size_t namespaceSize, + UA_String *serverUris, size_t serverUriSize, + UA_Boolean useReversible); + +UA_StatusCode UA_NetworkMessage_decodeJson(UA_NetworkMessage *dst, const UA_ByteString *src); +#endif + +_UA_END_DECLS + + +/**** amalgamated original file "/src/pubsub/ua_pubsub.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner) + * Copyright (c) 2019 Kalycito Infotech Private Limited + * Copyright (c) 2020 Yannick Wallerer, Siemens AG + * Copyright (c) 2020 Thomas Fischer, Siemens AG + * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes) + */ + + + + +/* The public configuration structs are defined in include/ua_plugin_pubsub.h */ + +_UA_BEGIN_DECLS + +#ifdef UA_ENABLE_PUBSUB + +struct UA_WriterGroup; +typedef struct UA_WriterGroup UA_WriterGroup; + +struct UA_ReaderGroup; +typedef struct UA_ReaderGroup UA_ReaderGroup; + +/**********************************************/ +/* PublishedDataSet */ +/**********************************************/ + +typedef struct UA_PublishedDataSet { + UA_PublishedDataSetConfig config; + UA_DataSetMetaDataType dataSetMetaData; + TAILQ_HEAD(UA_ListOfDataSetField, UA_DataSetField) fields; + UA_NodeId identifier; + UA_UInt16 fieldSize; + UA_UInt16 promotedFieldsCount; + UA_UInt16 configurationFreezeCounter; + TAILQ_ENTRY(UA_PublishedDataSet) listEntry; + UA_Boolean configurationFrozen; +} UA_PublishedDataSet; + +UA_StatusCode +UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src, + UA_PublishedDataSetConfig *dst); + +UA_PublishedDataSet * +UA_PublishedDataSet_findPDSbyId(UA_Server *server, UA_NodeId identifier); + +void +UA_PublishedDataSet_clear(UA_Server *server, + UA_PublishedDataSet *publishedDataSet); + +/**********************************************/ +/* Connection */ +/**********************************************/ + +typedef struct UA_PubSubConnection { + UA_PubSubComponentEnumType componentType; + UA_PubSubConnectionConfig *config; + UA_PubSubChannel *channel; + UA_NodeId identifier; + LIST_HEAD(UA_ListOfWriterGroup, UA_WriterGroup) writerGroups; + size_t writerGroupsSize; + LIST_HEAD(UA_ListOfPubSubReaderGroup, UA_ReaderGroup) readerGroups; + size_t readerGroupsSize; + TAILQ_ENTRY(UA_PubSubConnection) listEntry; + UA_UInt16 configurationFreezeCounter; + UA_Boolean isRegistered; /* Subscriber requires connection channel regist */ + UA_Boolean configurationFrozen; +} UA_PubSubConnection; + +UA_StatusCode +UA_PubSubConnectionConfig_copy(const UA_PubSubConnectionConfig *src, + UA_PubSubConnectionConfig *dst); + +UA_PubSubConnection * +UA_PubSubConnection_findConnectionbyId(UA_Server *server, + UA_NodeId connectionIdentifier); + +void +UA_PubSubConnectionConfig_clear(UA_PubSubConnectionConfig *connectionConfig); + +void +UA_PubSubConnection_clear(UA_Server *server, UA_PubSubConnection *connection); + +/* Register channel for given connectionIdentifier */ +UA_StatusCode +UA_PubSubConnection_regist(UA_Server *server, UA_NodeId *connectionIdentifier); + +/* Process Network Message for a ReaderGroup. But we the ReaderGroup needs to be + * identified first. */ +UA_StatusCode +UA_Server_processNetworkMessage(UA_Server *server, + UA_PubSubConnection *connection, + UA_NetworkMessage *msg); + +/**********************************************/ +/* DataSetWriter */ +/**********************************************/ + +#ifdef UA_ENABLE_PUBSUB_DELTAFRAMES +typedef struct UA_DataSetWriterSample { + UA_Boolean valueChanged; + UA_DataValue value; +} UA_DataSetWriterSample; +#endif + +typedef struct UA_DataSetWriter { + UA_PubSubComponentEnumType componentType; + UA_DataSetWriterConfig config; + LIST_ENTRY(UA_DataSetWriter) listEntry; + UA_NodeId identifier; + UA_NodeId linkedWriterGroup; + UA_NodeId connectedDataSet; + UA_ConfigurationVersionDataType connectedDataSetVersion; + UA_PubSubState state; +#ifdef UA_ENABLE_PUBSUB_DELTAFRAMES + UA_UInt16 deltaFrameCounter; /* count of sent deltaFrames */ + size_t lastSamplesCount; + UA_DataSetWriterSample *lastSamples; +#endif + UA_UInt16 actualDataSetMessageSequenceCount; + UA_Boolean configurationFrozen; +} UA_DataSetWriter; + +UA_StatusCode +UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src, + UA_DataSetWriterConfig *dst); + +UA_DataSetWriter * +UA_DataSetWriter_findDSWbyId(UA_Server *server, UA_NodeId identifier); + +UA_StatusCode +UA_DataSetWriter_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_DataSetWriter *dataSetWriter); + +UA_StatusCode +UA_DataSetWriter_generateDataSetMessage(UA_Server *server, + UA_DataSetMessage *dataSetMessage, + UA_DataSetWriter *dataSetWriter); + +UA_StatusCode +UA_DataSetWriter_remove(UA_Server *server, UA_WriterGroup *linkedWriterGroup, + UA_DataSetWriter *dataSetWriter); + +/**********************************************/ +/* WriterGroup */ +/**********************************************/ + +struct UA_WriterGroup { + UA_PubSubComponentEnumType componentType; + UA_WriterGroupConfig config; + LIST_ENTRY(UA_WriterGroup) listEntry; + UA_NodeId identifier; + UA_PubSubConnection *linkedConnection; + LIST_HEAD(UA_ListOfDataSetWriter, UA_DataSetWriter) writers; + UA_UInt32 writersCount; + UA_UInt64 publishCallbackId; + UA_Boolean publishCallbackIsRegistered; + UA_PubSubState state; + UA_NetworkMessageOffsetBuffer bufferedMessage; + UA_UInt16 sequenceNumber; /* Increased after every succressuly sent message */ + UA_Boolean configurationFrozen; + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_UInt32 securityTokenId; + UA_UInt32 nonceSequenceNumber; /* To be part of the MessageNonce */ + void *securityPolicyContext; +#endif +}; + +UA_StatusCode +UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src, + UA_WriterGroupConfig *dst); + +UA_WriterGroup * +UA_WriterGroup_findWGbyId(UA_Server *server, UA_NodeId identifier); + +UA_StatusCode +UA_WriterGroup_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_WriterGroup *writerGroup); + +/**********************************************/ +/* DataSetField */ +/**********************************************/ + +typedef struct UA_DataSetField { + UA_DataSetFieldConfig config; + TAILQ_ENTRY(UA_DataSetField) listEntry; + UA_NodeId identifier; + UA_NodeId publishedDataSet; /* parent pds */ + UA_FieldMetaData fieldMetaData; /* contains the dataSetFieldId */ + UA_UInt64 sampleCallbackId; + UA_Boolean sampleCallbackIsRegistered; + UA_Boolean configurationFrozen; +} UA_DataSetField; + +UA_StatusCode +UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src, + UA_DataSetFieldConfig *dst); + +UA_DataSetField * +UA_DataSetField_findDSFbyId(UA_Server *server, UA_NodeId identifier); + +/**********************************************/ +/* DataSetReader */ +/**********************************************/ + +/* DataSetReader Type definition */ +typedef struct UA_DataSetReader { + UA_PubSubComponentEnumType componentType; + UA_DataSetReaderConfig config; + UA_NodeId identifier; + UA_NodeId linkedReaderGroup; + LIST_ENTRY(UA_DataSetReader) listEntry; + + UA_PubSubState state; /* non std */ + UA_Boolean configurationFrozen; + UA_NetworkMessageOffsetBuffer bufferedMessage; + +#ifdef UA_ENABLE_PUBSUB_MONITORING + /* MessageReceiveTimeout handling */ + UA_ServerCallback msgRcvTimeoutTimerCallback; + UA_UInt64 msgRcvTimeoutTimerId; + UA_Boolean msgRcvTimeoutTimerRunning; +#endif +} UA_DataSetReader; + +/* Process Network Message using DataSetReader */ +void +UA_DataSetReader_process(UA_Server *server, + UA_ReaderGroup *readerGroup, + UA_DataSetReader *dataSetReader, + UA_DataSetMessage *dataSetMsg); + +/* Copy the configuration of DataSetReader */ +UA_StatusCode UA_DataSetReaderConfig_copy(const UA_DataSetReaderConfig *src, + UA_DataSetReaderConfig *dst); + +/* Clear the configuration of a DataSetReader */ +void UA_DataSetReaderConfig_clear(UA_DataSetReaderConfig *cfg); + +/* Copy the configuration of Target Variables */ +UA_StatusCode UA_TargetVariables_copy(const UA_TargetVariables *src, + UA_TargetVariables *dst); + +/* Clear the Target Variables configuration */ +void UA_TargetVariables_clear(UA_TargetVariables *subscribedDataSetTarget); + +/* Copy the configuration of Field Target Variables */ +UA_StatusCode UA_FieldTargetVariable_copy(const UA_FieldTargetVariable *src, + UA_FieldTargetVariable *dst); + +UA_StatusCode +UA_DataSetReader_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_DataSetReader *dataSetReader); + +#ifdef UA_ENABLE_PUBSUB_MONITORING +/* Check if DataSetReader has a message receive timeout */ +void +UA_DataSetReader_checkMessageReceiveTimeout(UA_Server *server, + UA_DataSetReader *dataSetReader); + +/* DataSetReader MessageReceiveTimeout callback for generic PubSub component + * timeout handling */ +void +UA_DataSetReader_handleMessageReceiveTimeout(UA_Server *server, + void *dataSetReader); +#endif /* UA_ENABLE_PUBSUB_MONITORING */ + +UA_StatusCode +UA_DataSetReader_generateNetworkMessage(UA_PubSubConnection *pubSubConnection, + UA_DataSetReader *dataSetReader, + UA_DataSetMessage *dsm, UA_UInt16 *writerId, + UA_Byte dsmCount, UA_NetworkMessage *nm); + +UA_StatusCode +UA_DataSetReader_generateDataSetMessage(UA_Server *server, + UA_DataSetMessage *dataSetMessage, + UA_DataSetReader *dataSetReader); + +/**********************************************/ +/* ReaderGroup */ +/**********************************************/ + +struct UA_ReaderGroup { + UA_PubSubComponentEnumType componentType; + UA_ReaderGroupConfig config; + UA_NodeId identifier; + UA_NodeId linkedConnection; + LIST_ENTRY(UA_ReaderGroup) listEntry; + LIST_HEAD(UA_ListOfPubSubDataSetReader, UA_DataSetReader) readers; + /* for simplified information access */ + UA_UInt32 readersCount; + UA_UInt64 subscribeCallbackId; + UA_PubSubState state; + UA_Boolean configurationFrozen; + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + UA_UInt32 securityTokenId; + UA_UInt32 nonceSequenceNumber; /* To be part of the MessageNonce */ + void *securityPolicyContext; +#endif +}; + +UA_StatusCode +UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src, + UA_ReaderGroupConfig *dst); + +/* Prototypes for internal util functions - some functions maybe removed later + * (currently moved from public to internal) */ +UA_ReaderGroup * +UA_ReaderGroup_findRGbyId(UA_Server *server, UA_NodeId identifier); + +UA_DataSetReader * +UA_ReaderGroup_findDSRbyId(UA_Server *server, UA_NodeId identifier); + +UA_StatusCode +UA_ReaderGroup_setPubSubState(UA_Server *server, UA_PubSubState state, + UA_ReaderGroup *readerGroup); + +/*********************************************************/ +/* PublishValues handling */ +/*********************************************************/ + +UA_StatusCode +UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup); + +void +UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup); + +/*********************************************************/ +/* SubscribeValues handling */ +/*********************************************************/ + +UA_StatusCode +UA_ReaderGroup_addSubscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup); + +void +UA_ReaderGroup_removeSubscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup); + +void +UA_ReaderGroup_subscribeCallback(UA_Server *server, UA_ReaderGroup *readerGroup); + +/*********************************************************/ +/* Reading Message handling */ +/*********************************************************/ + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION +UA_StatusCode +verifyAndDecrypt(const UA_Logger *logger, UA_ByteString *buffer, + const size_t *currentPosition, const UA_NetworkMessage *nm, + UA_Boolean doValidate, UA_Boolean doDecrypt, + void *channelContext, UA_PubSubSecurityPolicy *securityPolicy); + +UA_StatusCode +verifyAndDecryptNetworkMessage(const UA_Logger *logger, UA_ByteString *buffer, + size_t *currentPosition, UA_NetworkMessage *nm, + UA_ReaderGroup *readerGroup); +#endif + +/* Takes a value (and not a pointer) to the buffer. The original buffer is + const. Internally we may adjust the length during decryption. */ +UA_StatusCode +decodeNetworkMessage(UA_Server *server, UA_ByteString *buffer, size_t *pos, + UA_NetworkMessage *nm, UA_PubSubConnection *connection); + +UA_StatusCode +receiveBufferedNetworkMessage(UA_Server *server, UA_ReaderGroup *readerGroup, + UA_PubSubConnection *connection); + +#endif /* UA_ENABLE_PUBSUB */ + +_UA_END_DECLS + + +/**** amalgamated original file "/src/pubsub/ua_pubsub_manager.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner) + */ + + + + +_UA_BEGIN_DECLS + +#ifdef UA_ENABLE_PUBSUB /* conditional compilation */ + +typedef struct UA_PubSubManager { + /* Connections and PublishedDataSets can exist alone (own lifecycle) -> top + * level components */ + size_t connectionsSize; + TAILQ_HEAD(UA_ListOfPubSubConnection, UA_PubSubConnection) connections; + + size_t publishedDataSetsSize; + TAILQ_HEAD(UA_ListOfPublishedDataSet, UA_PublishedDataSet) publishedDataSets; + +#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL + UA_UInt32 uniqueIdCount; +#endif +} UA_PubSubManager; + +void +UA_PubSubManager_delete(UA_Server *server, UA_PubSubManager *pubSubManager); + +#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL +void +UA_PubSubManager_generateUniqueNodeId(UA_PubSubManager *psm, UA_NodeId *nodeId); +#endif + +UA_Guid +UA_PubSubManager_generateUniqueGuid(UA_Server *server); + +UA_UInt32 +UA_PubSubConfigurationVersionTimeDifference(void); + +/***********************************/ +/* PubSub Jobs abstraction */ +/***********************************/ +UA_StatusCode +UA_PubSubManager_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId); +UA_StatusCode +UA_PubSubManager_changeRepeatedCallback(UA_Server *server, UA_UInt64 callbackId, + UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy); +void +UA_PubSubManager_removeRepeatedPubSubCallback(UA_Server *server, UA_UInt64 callbackId); + +/*************************************************/ +/* PubSub component monitoring */ +/*************************************************/ + +#ifdef UA_ENABLE_PUBSUB_MONITORING + +UA_StatusCode +UA_PubSubManager_setDefaultMonitoringCallbacks(UA_PubSubMonitoringInterface *monitoringInterface); + +#endif /* UA_ENABLE_PUBSUB_MONITORING */ + +#endif /* UA_ENABLE_PUBSUB */ + +_UA_END_DECLS + + +/**** amalgamated original file "/src/pubsub/ua_pubsub_ns0.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner) + * Copyright (c) 2019 Kalycito Infotech Private Limited + */ + +#ifndef UA_PUBSUB_NS0_H_ +#define UA_PUBSUB_NS0_H_ + + +_UA_BEGIN_DECLS + +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */ + +UA_StatusCode +UA_Server_initPubSubNS0(UA_Server *server); + +UA_StatusCode +addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection); + +UA_StatusCode +removePubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection); + +UA_StatusCode +addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup); + +UA_StatusCode +addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup); + +UA_StatusCode +removeGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup); + +UA_StatusCode +addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter); + +UA_StatusCode +removeDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter); + +UA_StatusCode +addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet); + +UA_StatusCode +removePublishedDataSetRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet); + +UA_StatusCode +addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader); + +UA_StatusCode +removeDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader); + +UA_StatusCode +removeReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup); + +#endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */ + +_UA_END_DECLS + +#endif /* UA_PUBSUB_NS0_H_ */ + +/**** amalgamated original file "/src/server/ua_server_async.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2019 (c) Fraunhofer IOSB (Author: Klaus Schick) + * based on + * Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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_BEGIN_DECLS + +#if UA_MULTITHREADING >= 100 + +struct UA_AsyncResponse; +typedef struct UA_AsyncResponse UA_AsyncResponse; + +/* A single operation (of a larger request) */ +typedef struct UA_AsyncOperation { + TAILQ_ENTRY(UA_AsyncOperation) pointers; + UA_CallMethodRequest request; + UA_CallMethodResult response; + size_t index; /* Index of the operation in the array of ops in + * request/response */ + UA_AsyncResponse *parent; /* Always non-NULL. The parent is only removed + * when its operations are removed */ +} UA_AsyncOperation; + +struct UA_AsyncResponse { + TAILQ_ENTRY(UA_AsyncResponse) pointers; /* Insert new at the end */ + UA_UInt32 requestId; + UA_NodeId sessionId; + UA_UInt32 requestHandle; + UA_DateTime timeout; + UA_AsyncOperationType operationType; + union { + UA_CallResponse callResponse; + UA_ReadResponse readResponse; + UA_WriteResponse writeResponse; + } response; + UA_UInt32 opCountdown; /* Counter for outstanding operations. The AR can + * only be deleted when all have returned. */ +}; + +typedef TAILQ_HEAD(UA_AsyncOperationQueue, UA_AsyncOperation) UA_AsyncOperationQueue; + +typedef struct { + /* Requests / Responses */ + TAILQ_HEAD(, UA_AsyncResponse) asyncResponses; + size_t asyncResponsesCount; + + /* Operations for the workers. The queues are all FIFO: Put in at the tail, + * take out at the head.*/ + UA_Lock queueLock; + UA_AsyncOperationQueue newQueue; /* New operations for the workers */ + UA_AsyncOperationQueue dispatchedQueue; /* Operations taken by a worker. When a result is + * returned, we search for the op here to see if it + * is still "alive" (not timed out). */ + UA_AsyncOperationQueue resultQueue; /* Results to be integrated */ + size_t opsCount; /* How many operations are transient (in one of the three queues)? */ + + UA_UInt64 checkTimeoutCallbackId; /* Registered repeated callbacks */ +} UA_AsyncManager; + +void UA_AsyncManager_init(UA_AsyncManager *am, UA_Server *server); +void UA_AsyncManager_clear(UA_AsyncManager *am, UA_Server *server); + +UA_StatusCode +UA_AsyncManager_createAsyncResponse(UA_AsyncManager *am, UA_Server *server, + const UA_NodeId *sessionId, + const UA_UInt32 requestId, + const UA_UInt32 requestHandle, + const UA_AsyncOperationType operationType, + UA_AsyncResponse **outAr); + +/* Only remove the AsyncResponse when the operation count is zero */ +void +UA_AsyncManager_removeAsyncResponse(UA_AsyncManager *am, UA_AsyncResponse *ar); + +UA_StatusCode +UA_AsyncManager_createAsyncOp(UA_AsyncManager *am, UA_Server *server, + UA_AsyncResponse *ar, size_t opIndex, + const UA_CallMethodRequest *opRequest); + +typedef void (*UA_AsyncServiceOperation)(UA_Server *server, UA_Session *session, + UA_UInt32 requestId, UA_UInt32 requestHandle, + size_t opIndex, const void *requestOperation, + void *responseOperation, UA_AsyncResponse **ar); + +/* Creates an AsyncResponse in-situ when an async operation is encountered. If + * that is the case, the sync responses are moved to the AsyncResponse. */ +UA_StatusCode +UA_Server_processServiceOperationsAsync(UA_Server *server, UA_Session *session, + UA_UInt32 requestId, UA_UInt32 requestHandle, + UA_AsyncServiceOperation operationCallback, + const size_t *requestOperations, + const UA_DataType *requestOperationsType, + size_t *responseOperations, + const UA_DataType *responseOperationsType, + UA_AsyncResponse **ar) +UA_FUNC_ATTR_WARN_UNUSED_RESULT; + +#endif /* UA_MULTITHREADING >= 100 */ + +_UA_END_DECLS + + +/**** amalgamated original file "/src/server/ua_server_internal.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2019 (c) Fraunhofer IOSB (Author: Klaus Schick) + * Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + * Copyright 2019 (c) Kalycito Infotech Private Limited + * Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green) + */ + + + + +_UA_BEGIN_DECLS + +#if UA_MULTITHREADING >= 100 +#undef UA_THREADSAFE +#define UA_THREADSAFE UA_DEPRECATED +#endif + +#ifdef UA_ENABLE_PUBSUB +#endif + +#ifdef UA_ENABLE_DISCOVERY +#endif + +#ifdef UA_ENABLE_SUBSCRIPTIONS + +typedef struct { + UA_MonitoredItem monitoredItem; + void *context; + union { + UA_Server_DataChangeNotificationCallback dataChangeCallback; + /* UA_Server_EventNotificationCallback eventCallback; */ + } callback; +} UA_LocalMonitoredItem; + +#endif + +typedef enum { + UA_DIAGNOSTICEVENT_CLOSE, + UA_DIAGNOSTICEVENT_REJECT, + UA_DIAGNOSTICEVENT_SECURITYREJECT, + UA_DIAGNOSTICEVENT_TIMEOUT, + UA_DIAGNOSTICEVENT_ABORT, + UA_DIAGNOSTICEVENT_PURGE +} UA_DiagnosticEvent; + +typedef struct channel_entry { + UA_TimerEntry cleanupCallback; + TAILQ_ENTRY(channel_entry) pointers; + UA_SecureChannel channel; +} channel_entry; + +typedef struct session_list_entry { + UA_TimerEntry cleanupCallback; + LIST_ENTRY(session_list_entry) pointers; + UA_Session session; +} session_list_entry; + +typedef enum { + UA_SERVERLIFECYCLE_FRESH, + UA_SERVERLIFECYLE_RUNNING +} UA_ServerLifecycle; + +struct UA_Server { + /* Config */ + UA_ServerConfig config; + UA_DateTime startTime; + UA_DateTime endTime; /* Zeroed out. If a time is set, then the server shuts + * down once the time has been reached */ + + UA_ServerLifecycle state; + + /* SecureChannels */ + TAILQ_HEAD(, channel_entry) channels; + UA_UInt32 lastChannelId; + UA_UInt32 lastTokenId; + +#if UA_MULTITHREADING >= 100 + UA_AsyncManager asyncManager; +#endif + + /* Session Management */ + LIST_HEAD(session_list, session_list_entry) sessions; + UA_UInt32 sessionCount; + UA_Session adminSession; /* Local access to the services (for startup and + * maintenance) uses this Session with all possible + * access rights (Session Id: 1) */ + + /* Namespaces */ + size_t namespacesSize; + UA_String *namespaces; + + /* Callbacks with a repetition interval */ + UA_Timer timer; + + /* For bootstrapping, omit some consistency checks, creating a reference to + * the parent and member instantiation */ + UA_Boolean bootstrapNS0; + + /* Discovery */ +#ifdef UA_ENABLE_DISCOVERY + UA_DiscoveryManager discoveryManager; +#endif + + /* Subscriptions */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + size_t subscriptionsSize; /* Number of active subscriptions */ + size_t monitoredItemsSize; /* Number of active monitored items */ + LIST_HEAD(, UA_Subscription) subscriptions; /* All subscriptions in the + * server. They may be detached + * from a session. */ + UA_UInt32 lastSubscriptionId; /* To generate unique SubscriptionIds */ + + /* To be cast to UA_LocalMonitoredItem to get the callback and context */ + LIST_HEAD(, UA_MonitoredItem) localMonitoredItems; + UA_UInt32 lastLocalMonitoredItemId; + +# ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS + LIST_HEAD(, UA_ConditionSource) conditionSources; +# endif + +#endif + + /* Publish/Subscribe */ +#ifdef UA_ENABLE_PUBSUB + UA_PubSubManager pubSubManager; +#endif + +#if UA_MULTITHREADING >= 100 + UA_Lock networkMutex; + UA_Lock serviceMutex; +#endif + + /* Statistics */ + UA_ServerStatistics serverStats; +}; + +/***********************/ +/* References Handling */ +/***********************/ + +extern const struct aa_head refNameTree; + +const UA_ReferenceTarget * +UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk, + const UA_ExpandedNodeId *targetId); + +/**************************/ +/* SecureChannel Handling */ +/**************************/ + +/* Remove all securechannels */ +void +UA_Server_deleteSecureChannels(UA_Server *server); + +/* Remove timed out securechannels with a delayed callback. So all currently + * scheduled jobs with a pointer to a securechannel can finish first. */ +void +UA_Server_cleanupTimedOutSecureChannels(UA_Server *server, UA_DateTime nowMonotonic); + +UA_StatusCode +UA_Server_createSecureChannel(UA_Server *server, UA_Connection *connection); + +UA_StatusCode +UA_Server_configSecureChannel(void *application, UA_SecureChannel *channel, + const UA_AsymmetricAlgorithmSecurityHeader *asymHeader); + +UA_StatusCode +sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, UA_UInt32 requestHandle, + const UA_DataType *responseType, UA_StatusCode statusCode); + +void +UA_Server_closeSecureChannel(UA_Server *server, UA_SecureChannel *channel, + UA_DiagnosticEvent event); + +/* Gets the a pointer to the context of a security policy supported by the + * server matched by the security policy uri. */ +UA_SecurityPolicy * +getSecurityPolicyByUri(const UA_Server *server, + const UA_ByteString *securityPolicyUri); + + +/********************/ +/* Session Handling */ +/********************/ + +UA_StatusCode +getNamespaceByName(UA_Server *server, const UA_String namespaceUri, + size_t *foundIndex); + +UA_StatusCode +getBoundSession(UA_Server *server, const UA_SecureChannel *channel, + const UA_NodeId *token, UA_Session **session); + +UA_StatusCode +UA_Server_createSession(UA_Server *server, UA_SecureChannel *channel, + const UA_CreateSessionRequest *request, UA_Session **session); + +void +UA_Server_removeSession(UA_Server *server, session_list_entry *sentry, + UA_DiagnosticEvent event); + +UA_StatusCode +UA_Server_removeSessionByToken(UA_Server *server, const UA_NodeId *token, + UA_DiagnosticEvent event); + +void +UA_Server_cleanupSessions(UA_Server *server, UA_DateTime nowMonotonic); + +UA_Session * +getSessionByToken(UA_Server *server, const UA_NodeId *token); + +UA_Session * +UA_Server_getSessionById(UA_Server *server, const UA_NodeId *sessionId); + +/*****************/ +/* Node Handling */ +/*****************/ + +/* 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); + +/*********************/ +/* Utility Functions */ +/*********************/ + +void setupNs1Uri(UA_Server *server); +UA_UInt16 addNamespace(UA_Server *server, const UA_String name); + +UA_Boolean +UA_Node_hasSubTypeOrInstances(const UA_NodeHead *head); + +/* Recursively searches "upwards" in the tree following specific reference types */ +UA_Boolean +isNodeInTree(UA_Server *server, const UA_NodeId *leafNode, + const UA_NodeId *nodeToFind, const UA_ReferenceTypeSet *relevantRefs); + +/* Convenience function with just a single ReferenceTypeIndex */ +UA_Boolean +isNodeInTree_singleRef(UA_Server *server, const UA_NodeId *leafNode, + const UA_NodeId *nodeToFind, const UA_Byte relevantRefTypeIndex); + +/* Returns an array with the hierarchy of nodes. The start nodes can be returned + * as well. The returned array starts at the leaf and continues "upwards" or + * "downwards". Duplicate entries are removed. */ +UA_StatusCode +browseRecursive(UA_Server *server, size_t startNodesSize, const UA_NodeId *startNodes, + UA_BrowseDirection browseDirection, const UA_ReferenceTypeSet *refTypes, + UA_UInt32 nodeClassMask, UA_Boolean includeStartNodes, + size_t *resultsSize, UA_ExpandedNodeId **results); + +/* Get the bitfield indices of a ReferenceType and possibly its subtypes. + * refType must point to a ReferenceTypeNode. */ +UA_StatusCode +referenceTypeIndices(UA_Server *server, const UA_NodeId *refType, + UA_ReferenceTypeSet *indices, UA_Boolean includeSubtypes); + +/* Returns the recursive type and interface hierarchy of the node */ +UA_StatusCode +getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode, + UA_NodeId **typeHierarchy, size_t *typeHierarchySize); + +/* Returns the recursive interface hierarchy of the node */ +UA_StatusCode +getAllInterfaceChildNodeIds(UA_Server *server, const UA_NodeId *objectNode, const UA_NodeId *objectTypeNode, + UA_NodeId **interfaceChildNodes, size_t *interfaceChildNodesSize); + +#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS + +UA_StatusCode +UA_getConditionId(UA_Server *server, const UA_NodeId *conditionNodeId, + UA_NodeId *outConditionId); + +void +UA_ConditionList_delete(UA_Server *server); + +UA_Boolean +isConditionOrBranch(UA_Server *server, + const UA_NodeId *condition, + const UA_NodeId *conditionSource, + UA_Boolean *isCallerAC); + +#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */ + +/* Returns the type node from the node on the stack top. The type node is pushed + * on the stack and returned. */ +const UA_Node * +getNodeType(UA_Server *server, const UA_NodeHead *nodeHead); + +UA_StatusCode +sendResponse(UA_Server *server, UA_Session *session, UA_SecureChannel *channel, + UA_UInt32 requestId, UA_Response *response, const UA_DataType *responseType); + +/* 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, + const void *context, + const void *requestOperation, + void *responseOperation); + +UA_StatusCode +UA_Server_processServiceOperations(UA_Server *server, UA_Session *session, + UA_ServiceOperation operationCallback, + const void *context, + const size_t *requestOperations, + const UA_DataType *requestOperationsType, + size_t *responseOperations, + const UA_DataType *responseOperationsType) + UA_FUNC_ATTR_WARN_UNUSED_RESULT; + +/******************************************/ +/* Internal function calls, without locks */ +/******************************************/ +UA_StatusCode +deleteNode(UA_Server *server, const UA_NodeId nodeId, + UA_Boolean deleteReferences); + +UA_StatusCode +addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId *requestedNewNodeId, + const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId, + const UA_QualifiedName browseName, const UA_NodeId *typeDefinition, + const UA_NodeAttributes *attr, const UA_DataType *attributeType, + void *nodeContext, UA_NodeId *outNewNodeId); + +UA_StatusCode +setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId, + const UA_DataSource dataSource); + +UA_StatusCode +writeAttribute(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, const UA_AttributeId attributeId, + const void *attr, const UA_DataType *attr_type); + +static UA_INLINE UA_StatusCode +writeValueAttribute(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, const UA_Variant *value) { + return writeAttribute(server, session, nodeId, UA_ATTRIBUTEID_VALUE, + value, &UA_TYPES[UA_TYPES_VARIANT]); +} + +UA_DataValue +readAttribute(UA_Server *server, const UA_ReadValueId *item, + UA_TimestampsToReturn timestamps); + +UA_StatusCode +readWithReadValue(UA_Server *server, const UA_NodeId *nodeId, + const UA_AttributeId attributeId, void *v); + +UA_StatusCode +readObjectProperty(UA_Server *server, const UA_NodeId objectId, + const UA_QualifiedName propertyName, + UA_Variant *value); + +UA_BrowsePathResult +translateBrowsePathToNodeIds(UA_Server *server, const UA_BrowsePath *browsePath); + +#ifdef UA_ENABLE_SUBSCRIPTIONS + +void monitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem); + +UA_Subscription * +UA_Server_getSubscriptionById(UA_Server *server, UA_UInt32 subscriptionId); + +UA_StatusCode +triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, + const UA_NodeId origin, UA_ByteString *outEventId, + const UA_Boolean deleteEventNode); + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +UA_BrowsePathResult +browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin, + size_t browsePathSize, const UA_QualifiedName *browsePath); + +UA_StatusCode +writeObjectProperty(UA_Server *server, const UA_NodeId objectId, + const UA_QualifiedName propertyName, const UA_Variant value); + +UA_StatusCode +getNodeContext(UA_Server *server, UA_NodeId nodeId, void **nodeContext); + +void +removeCallback(UA_Server *server, UA_UInt64 callbackId); + +UA_StatusCode +changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, UA_Double interval_ms); + +UA_StatusCode +addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_Double interval_ms, UA_UInt64 *callbackId); + +#ifdef UA_ENABLE_DISCOVERY +UA_StatusCode +register_server_with_discovery_server(UA_Server *server, + void *client, + const UA_Boolean isUnregister, + const char* semaphoreFilePath); +#endif + +/***********/ +/* RefTree */ +/***********/ + +/* A RefTree is a sorted set of NodeIds that ensures we consider each node just + * once. It holds a single array for both the ExpandedNodeIds and the entries of + * a tree-structure for fast lookup. A single realloc operation (with some + * pointer repairing) can be used to increase the capacity of the RefTree. + * + * When the RefTree is complete, the tree-part at the end of the targets array + * can be ignored / cut away to use it as a simple ExpandedNodeId array. + * + * The layout of the targets array is as follows: + * + * | Targets [ExpandedNodeId, n times] | Tree [RefEntry, n times] | */ + +#define UA_REFTREE_INITIAL_SIZE 16 + +typedef struct RefEntry { + ZIP_ENTRY(RefEntry) zipfields; + const UA_ExpandedNodeId *target; + UA_UInt32 targetHash; /* Hash of the target nodeid */ +} RefEntry; + +ZIP_HEAD(RefHead, RefEntry); +typedef struct RefHead RefHead; + +typedef struct { + UA_ExpandedNodeId *targets; + RefHead head; + size_t capacity; /* available space */ + size_t size; /* used space */ +} RefTree; + +UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT +RefTree_init(RefTree *rt); + +void RefTree_clear(RefTree *rt); + +UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT +RefTree_addNodeId(RefTree *rt, const UA_NodeId *target, UA_Boolean *duplicate); + +UA_Boolean +RefTree_contains(RefTree *rt, const UA_ExpandedNodeId *target); + +UA_Boolean +RefTree_containsNodeId(RefTree *rt, const UA_NodeId *target); + +/***************************************/ +/* Check Information Model Consistency */ +/***************************************/ + +/* Read a node attribute in the context of a "checked-out" node. So the + * attribute will not be copied when possible. The variant then points into the + * node and has UA_VARIANT_DATA_NODELETE set. */ +void +ReadWithNode(const UA_Node *node, UA_Server *server, UA_Session *session, + UA_TimestampsToReturn timestampsToReturn, + const UA_ReadValueId *id, UA_DataValue *v); + +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); + +/* Is the DataType compatible */ +UA_Boolean +compatibleDataTypes(UA_Server *server, const UA_NodeId *dataType, + const UA_NodeId *constraintDataType); + +/* Set to the target type if compatible */ +void +adjustValueType(UA_Server *server, UA_Variant *value, + const UA_NodeId *targetDataTypeId); + +/* Is the Value compatible with the DataType? Can perform additional checks + * compared to compatibleDataTypes. */ +UA_Boolean +compatibleValueDataType(UA_Server *server, const UA_DataType *dataType, + const UA_NodeId *constraintDataType); + + +UA_Boolean +compatibleArrayDimensions(size_t constraintArrayDimensionsSize, + 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 +compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank); + +struct BrowseOpts { + UA_UInt32 maxReferences; + UA_Boolean recursive; +}; + +void +Operation_Browse(UA_Server *server, UA_Session *session, const 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); + +/*****************************/ +/* AddNodes Begin and Finish */ +/*****************************/ + +/* Creates a new node in the nodestore. */ +UA_StatusCode +AddNode_raw(UA_Server *server, UA_Session *session, void *nodeContext, + const UA_AddNodesItem *item, UA_NodeId *outNewNodeId); + +/* Check the reference to the parent node; Add references. */ +UA_StatusCode +AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, + const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId, + const UA_NodeId *typeDefinitionId); + +/* Type-check type-definition; Run the constructors */ +UA_StatusCode +AddNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId); + +/**********************/ +/* Create Namespace 0 */ +/**********************/ + +UA_StatusCode UA_Server_initNS0(UA_Server *server); + +UA_StatusCode writeNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v, + size_t length, const UA_DataType *type); + +/***************************/ +/* Nodestore Access Macros */ +/***************************/ + +#define UA_NODESTORE_NEW(server, nodeClass) \ + server->config.nodestore.newNode(server->config.nodestore.context, nodeClass) + +#define UA_NODESTORE_DELETE(server, node) \ + server->config.nodestore.deleteNode(server->config.nodestore.context, node) + +#define UA_NODESTORE_GET(server, nodeid) \ + server->config.nodestore.getNode(server->config.nodestore.context, nodeid) + +/* Returns NULL if the target is an external Reference (per the ExpandedNodeId) */ +const UA_Node * +UA_NODESTORE_GETFROMREF(UA_Server *server, UA_NodePointer target); + +#define UA_NODESTORE_RELEASE(server, node) \ + server->config.nodestore.releaseNode(server->config.nodestore.context, node) + +#define UA_NODESTORE_GETCOPY(server, nodeid, outnode) \ + server->config.nodestore.getNodeCopy(server->config.nodestore.context, \ + nodeid, outnode) + +#define UA_NODESTORE_INSERT(server, node, addedNodeId) \ + server->config.nodestore.insertNode(server->config.nodestore.context, \ + node, addedNodeId) + +#define UA_NODESTORE_REPLACE(server, node) \ + server->config.nodestore.replaceNode(server->config.nodestore.context, node) + +#define UA_NODESTORE_REMOVE(server, nodeId) \ + server->config.nodestore.removeNode(server->config.nodestore.context, nodeId) + +#define UA_NODESTORE_GETREFERENCETYPEID(server, index) \ + server->config.nodestore.getReferenceTypeId(server->config.nodestore.context, \ + index) + +_UA_END_DECLS + + +/**** amalgamated original file "/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) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + */ + + + + +_UA_BEGIN_DECLS + +/** + * .. _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 ` 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 void (*UA_ChannelService)(UA_Server*, UA_SecureChannel*, + const void *request, void *response); + +/** + * 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 servers which may have been detected through 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, + const UA_ActivateSessionRequest *request, + UA_ActivateSessionResponse *response); + +/** + * CloseSession + * ^^^^^^^^^^^^ + * Used to terminate a Session. */ +void Service_CloseSession(UA_Server *server, UA_SecureChannel *channel, + 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. + * If the type or one of the supertypes has any HasInterface references + * (see OPC 10001-7 - Amendment 7, 4.9.2), the child nodes of the interfaces + * are added to the new object. +*/ +void Service_AddNodes(UA_Server *server, UA_Session *session, + const UA_AddNodesRequest *request, + UA_AddNodesResponse *response); + +/** + * 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. */ +void Service_Read(UA_Server *server, UA_Session *session, + const UA_ReadRequest *request, + UA_ReadResponse *response); + +/** + * 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. */ +#ifdef UA_ENABLE_HISTORIZING +void Service_HistoryRead(UA_Server *server, UA_Session *session, + const UA_HistoryReadRequest *request, + UA_HistoryReadResponse *response); + +/** + * 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. */ +void +Service_HistoryUpdate(UA_Server *server, UA_Session *session, + const UA_HistoryUpdateRequest *request, + UA_HistoryUpdateResponse *response); +#endif + +/** + * .. _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 ` + * 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. */ +#ifdef UA_ENABLE_METHODCALLS +void Service_Call(UA_Server *server, UA_Session *session, + const UA_CallRequest *request, + UA_CallResponse *response); + +# if UA_MULTITHREADING >= 100 +void Service_CallAsync(UA_Server *server, UA_Session *session, UA_UInt32 requestId, + const UA_CallRequest *request, UA_CallResponse *response, + UA_Boolean *finished); +#endif +#endif + +#ifdef UA_ENABLE_SUBSCRIPTIONS + +/** + * 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. */ +void Service_SetTriggering(UA_Server *server, UA_Session *session, + const UA_SetTriggeringRequest *request, + UA_SetTriggeringResponse *response); + +/** + * 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. */ +void Service_TransferSubscriptions(UA_Server *server, UA_Session *session, + const UA_TransferSubscriptionsRequest *request, + UA_TransferSubscriptionsResponse *response); + +#endif /* UA_ENABLE_SUBSCRIPTIONS */ + +_UA_END_DECLS + + +/**** amalgamated original file "/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) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + */ + + +#define UA_INTERNAL + + +_UA_BEGIN_DECLS + +/**************************/ +/* 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_Client_MonitoredItem) monitoredItems; +} UA_Client_Subscription; + +void +UA_Client_Subscriptions_clean(UA_Client *client); + +/* Exposed for fuzzing */ +UA_StatusCode +UA_Client_preparePublishRequest(UA_Client *client, UA_PublishRequest *request); + +void +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; + void *responsedata; +} 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 struct CustomCallback { + UA_UInt32 callbackId; + + UA_ClientAsyncServiceCallback userCallback; + void *userData; + + void *clientData; +} CustomCallback; + +struct UA_Client { + UA_ClientConfig config; + UA_Timer timer; + + /* Overall connection status */ + UA_StatusCode connectStatus; + + /* Old status to notify only changes */ + UA_SecureChannelState oldChannelState; + UA_SessionState oldSessionState; + UA_StatusCode oldConnectStatus; + + UA_Boolean endpointsHandshake; /* Ongoing GetEndpoints */ + UA_Boolean noSession; /* Don't open a session */ + + /* Connection */ + UA_Connection connection; + UA_String endpointUrl; /* Only for the async connect */ + + /* SecureChannel */ + UA_SecureChannel channel; + UA_UInt32 requestId; + UA_DateTime nextChannelRenewal; + + /* Session */ + UA_SessionState sessionState; + UA_NodeId authenticationToken; + UA_UInt32 requestHandle; + UA_ByteString remoteNonce; + UA_ByteString localNonce; + + /* Connectivity check */ + UA_DateTime lastConnectivityCheck; + UA_Boolean pendingConnectivityCheck; + + /* Async Service */ + LIST_HEAD(, AsyncServiceCall) asyncServiceCalls; + + /* Subscriptions */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + LIST_HEAD(, UA_Client_NotificationsAckNumber) pendingNotificationsAcks; + LIST_HEAD(, UA_Client_Subscription) subscriptions; + UA_UInt32 monitoredItemHandles; + UA_UInt16 currentlyOutStandingPublishRequests; +#endif +}; + +void notifyClientState(UA_Client *client); +void processERRResponse(UA_Client *client, const UA_ByteString *chunk); +void processACKResponse(UA_Client *client, const UA_ByteString *chunk); +void processOPNResponse(UA_Client *client, const UA_ByteString *message); +void closeSecureChannel(UA_Client *client); + +UA_StatusCode +connectIterate(UA_Client *client, UA_UInt32 timeout); + +UA_StatusCode +receiveResponseAsync(UA_Client *client, UA_UInt32 timeout); + +_UA_END_DECLS + + +/**** amalgamated original file "/src/pubsub/ua_pubsub_config.h" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2020 Yannick Wallerer, Siemens AG + * Copyright (c) 2020 Thomas Fischer, Siemens AG + */ + +#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG + + + +/* Decodes the information from the ByteString. If the decoded content is a + * PubSubConfiguration in a UABinaryFileDataType-object. It will overwrite the + * current PubSub configuration from the server. */ +UA_StatusCode +UA_PubSubManager_loadPubSubConfigFromByteString(UA_Server *server, + const UA_ByteString buffer); + +/* Saves the current PubSub configuration of a server in a byteString. */ +UA_StatusCode +UA_PubSubManager_getEncodedPubSubConfiguration(UA_Server *server, + UA_ByteString *buffer); + + +#endif /* UA_ENABLE_PUBSUB_FILE_CONFIG */ + +/**** amalgamated original file "/build_freeRTOS/src_generated/open62541/namespace0_generated.h" ****/ + +/* WARNING: This is a generated file. + * Any manual changes will be overwritten. */ + +#ifndef NAMESPACE0_GENERATED_H_ +#define NAMESPACE0_GENERATED_H_ + + +#ifdef UA_ENABLE_AMALGAMATION + +/* The following declarations are in the open62541.c file so here's needed when compiling nodesets externally */ + +# ifndef UA_INTERNAL //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_INTERNAL + +#else // UA_ENABLE_AMALGAMATION +#endif + + + + +_UA_BEGIN_DECLS + +extern UA_StatusCode namespace0_generated(UA_Server *server); + +_UA_END_DECLS + +#endif /* NAMESPACE0_GENERATED_H_ */ + +/**** amalgamated original file "/src/ua_types.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020 (c) Fraunhofer IOSB (Author: Andreas Ebner) + * Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + */ + + + +#define UA_MAX_ARRAY_DIMS 100 /* Max dimensions of an array */ + +/* 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}; +const UA_ByteString UA_BYTESTRING_NULL = {0}; +const UA_Guid UA_GUID_NULL = {0}; +const UA_NodeId UA_NODEID_NULL = {0}; +const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL = {0}; + +typedef UA_StatusCode +(*UA_copySignature)(const void *src, void *dst, const UA_DataType *type); +extern const UA_copySignature copyJumpTable[UA_DATATYPEKINDS]; + +typedef void (*UA_clearSignature)(void *p, const UA_DataType *type); +extern const UA_clearSignature clearJumpTable[UA_DATATYPEKINDS]; + +typedef UA_Order +(*UA_orderSignature)(const void *p1, const void *p2, const UA_DataType *type); +extern const UA_orderSignature orderJumpTable[UA_DATATYPEKINDS]; + +const UA_DataType * +UA_findDataTypeWithCustom(const UA_NodeId *typeId, + const UA_DataTypeArray *customTypes) { + /* Always look in built-in types first (may contain data types from all + * namespaces). + * + * TODO: The standard-defined types are ordered. See if binary search is + * more efficient. */ + for(size_t i = 0; i < UA_TYPES_COUNT; ++i) { + if(UA_NodeId_equal(&UA_TYPES[i].typeId, typeId)) + return &UA_TYPES[i]; + } + + /* Search in the customTypes */ + while(customTypes) { + for(size_t i = 0; i < customTypes->typesSize; ++i) { + if(UA_NodeId_equal(&customTypes->types[i].typeId, typeId)) + return &customTypes->types[i]; + } + customTypes = customTypes->next; + } + + return NULL; +} + +const UA_DataType * +UA_findDataType(const UA_NodeId *typeId) { + return UA_findDataTypeWithCustom(typeId, NULL); +} + +/***************************/ +/* Random Number Generator */ +/***************************/ + +//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 */ +/*****************/ + +UA_String +UA_String_fromChars(const char *src) { + UA_String s; s.length = 0; s.data = NULL; + if(!src) + return s; + s.length = strlen(src); + if(s.length > 0) { + s.data = (u8*)UA_malloc(s.length); + if(UA_UNLIKELY(!s.data)) { + s.length = 0; + return s; + } + memcpy(s.data, src, s.length); + } else { + s.data = (u8*)UA_EMPTY_ARRAY_SENTINEL; + } + return s; +} + +static UA_Order +stringOrder(const UA_String *p1, const UA_String *p2, const UA_DataType *type); +static UA_Order +guidOrder(const UA_Guid *p1, const UA_Guid *p2, const UA_DataType *type); +static UA_Order +qualifiedNameOrder(const UA_QualifiedName *p1, const UA_QualifiedName *p2, + const UA_DataType *type); + +UA_Boolean +UA_String_equal(const UA_String *s1, const UA_String *s2) { + return (stringOrder(s1, s2, NULL) == UA_ORDER_EQ); +} + +/* Do not expose UA_String_equal_ignorecase to public API as it currently only handles + * ASCII strings, and not UTF8! */ +UA_Boolean +UA_String_equal_ignorecase(const UA_String *s1, const UA_String *s2) { + if(s1->length != s2->length) + return false; + if(s1->length == 0) + return true; + if(s2->data == NULL) + return false; + + //FIXME this currently does not handle UTF8 + return UA_strncasecmp((const char*)s1->data, (const char*)s2->data, s1->length) == 0; +} + +static UA_StatusCode +String_copy(UA_String const *src, UA_String *dst, const UA_DataType *_) { + UA_StatusCode res = + UA_Array_copy(src->data, src->length, (void**)&dst->data, + &UA_TYPES[UA_TYPES_BYTE]); + if(res == UA_STATUSCODE_GOOD) + dst->length = src->length; + return res; +} + +static void +String_clear(UA_String *s, const UA_DataType *_) { + UA_Array_delete(s->data, s->length, &UA_TYPES[UA_TYPES_BYTE]); +} + +/* QualifiedName */ +static UA_StatusCode +QualifiedName_copy(const UA_QualifiedName *src, UA_QualifiedName *dst, + const UA_DataType *_) { + dst->namespaceIndex = src->namespaceIndex; + return String_copy(&src->name, &dst->name, NULL); +} + +static void +QualifiedName_clear(UA_QualifiedName *p, const UA_DataType *_) { + String_clear(&p->name, NULL); +} + +u32 +UA_QualifiedName_hash(const UA_QualifiedName *q) { + return UA_ByteString_hash(q->namespaceIndex, + q->name.data, q->name.length); +} + +UA_Boolean +UA_QualifiedName_equal(const UA_QualifiedName *qn1, + const UA_QualifiedName *qn2) { + return (qualifiedNameOrder(qn1, qn2, NULL) == UA_ORDER_EQ); +} + +/* DateTime */ +UA_DateTimeStruct +UA_DateTime_toStruct(UA_DateTime t) { + /* Calculating the the milli-, micro- and nanoseconds */ + UA_DateTimeStruct dateTimeStruct; + if(t >= 0) { + dateTimeStruct.nanoSec = (u16)((t % 10) * 100); + dateTimeStruct.microSec = (u16)((t % 10000) / 10); + dateTimeStruct.milliSec = (u16)((t % 10000000) / 10000); + } else { + dateTimeStruct.nanoSec = (u16)(((t % 10 + t) % 10) * 100); + dateTimeStruct.microSec = (u16)(((t % 10000 + t) % 10000) / 10); + dateTimeStruct.milliSec = (u16)(((t % 10000000 + t) % 10000000) / 10000); + } + + /* Calculating the unix time with #include */ + long long secSinceUnixEpoch = (long long)(t / UA_DATETIME_SEC) + - (long long)(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; +} + +UA_DateTime +UA_DateTime_fromStruct(UA_DateTimeStruct ts) { + /* Seconds since the Unix epoch */ + struct mytm tm; + memset(&tm, 0, sizeof(struct mytm)); + tm.tm_year = ts.year - 1900; + tm.tm_mon = ts.month - 1; + tm.tm_mday = ts.day; + tm.tm_hour = ts.hour; + tm.tm_min = ts.min; + tm.tm_sec = ts.sec; + long long sec_epoch = __tm_to_secs(&tm); + + UA_DateTime t = UA_DATETIME_UNIX_EPOCH; + t += sec_epoch * UA_DATETIME_SEC; + t += ts.milliSec * UA_DATETIME_MSEC; + t += ts.microSec * UA_DATETIME_USEC; + t += ts.nanoSec / 100; + return t; +} + +/* Guid */ +UA_Boolean +UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2) { + return (guidOrder(g1, g2, NULL) == UA_ORDER_EQ); +} + +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; + + if(length <= 8192) + length = length << 1; + bs->data = (u8*)UA_malloc(length); + if(UA_UNLIKELY(!bs->data)) + { + return UA_STATUSCODE_BADOUTOFMEMORY; + } + bs->length = length; + return UA_STATUSCODE_GOOD; +} + +/* NodeId */ +static void +NodeId_clear(UA_NodeId *p, const UA_DataType *_) { + switch(p->identifierType) { + case UA_NODEIDTYPE_STRING: + case UA_NODEIDTYPE_BYTESTRING: + String_clear(&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; +} + +/* Absolute ordering for NodeIds */ +UA_Order +UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2) { + /* Compare namespaceIndex */ + if(n1->namespaceIndex != n2->namespaceIndex) + return (n1->namespaceIndex < n2->namespaceIndex) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* Compare identifierType */ + if(n1->identifierType != n2->identifierType) + return (n1->identifierType < n2->identifierType) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* Compare the identifier */ + switch(n1->identifierType) { + case UA_NODEIDTYPE_NUMERIC: + default: + if(n1->identifier.numeric != n2->identifier.numeric) + return (n1->identifier.numeric < n2->identifier.numeric) ? + UA_ORDER_LESS : UA_ORDER_MORE; + return UA_ORDER_EQ; + + case UA_NODEIDTYPE_GUID: + return guidOrder(&n1->identifier.guid, &n2->identifier.guid, NULL); + + case UA_NODEIDTYPE_STRING: + case UA_NODEIDTYPE_BYTESTRING: + return stringOrder(&n1->identifier.string, &n2->identifier.string, NULL); + } +} + +/* sdbm-hash (http://www.cse.yorku.ca/~oz/hash.html) */ +u32 +UA_ByteString_hash(u32 initialHashValue, + const u8 *data, size_t size) { + u32 h = initialHashValue; + for(size_t i = 0; i < size; i++) + h = data[i] + (h << 6) + (h << 16) - h; + return h; +} + +u32 +UA_NodeId_hash(const UA_NodeId *n) { + switch(n->identifierType) { + case UA_NODEIDTYPE_NUMERIC: + default: + return UA_ByteString_hash(n->namespaceIndex, (const u8*)&n->identifier.numeric, + sizeof(UA_UInt32)); + case UA_NODEIDTYPE_STRING: + case UA_NODEIDTYPE_BYTESTRING: + return UA_ByteString_hash(n->namespaceIndex, n->identifier.string.data, + n->identifier.string.length); + case UA_NODEIDTYPE_GUID: + return UA_ByteString_hash(n->namespaceIndex, (const u8*)&n->identifier.guid, + sizeof(UA_Guid)); + } +} + +/* ExpandedNodeId */ +static void +ExpandedNodeId_clear(UA_ExpandedNodeId *p, const UA_DataType *_) { + NodeId_clear(&p->nodeId, _); + String_clear(&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; +} + +UA_Boolean +UA_ExpandedNodeId_isLocal(const UA_ExpandedNodeId *n) { + return (n->namespaceUri.length == 0 && n->serverIndex == 0); +} + +UA_Order +UA_ExpandedNodeId_order(const UA_ExpandedNodeId *n1, + const UA_ExpandedNodeId *n2) { + if(n1->serverIndex != n2->serverIndex) + return (n1->serverIndex < n2->serverIndex) ? UA_ORDER_LESS : UA_ORDER_MORE; + UA_Order o = stringOrder(&n1->namespaceUri, &n2->namespaceUri, NULL); + if(o != UA_ORDER_EQ) + return o; + return UA_NodeId_order(&n1->nodeId, &n2->nodeId); +} + +u32 +UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n) { + u32 h = UA_NodeId_hash(&n->nodeId); + if(n->serverIndex != 0) + h = UA_ByteString_hash(h, (const UA_Byte*)&n->serverIndex, 4); + if(n->namespaceUri.length != 0) + h = UA_ByteString_hash(h, n->namespaceUri.data, n->namespaceUri.length); + return h; +} + +/* ExtensionObject */ +static void +ExtensionObject_clear(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_clear(&p->content.encoded.typeId, NULL); + String_clear(&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; +} + +void +UA_ExtensionObject_setValue(UA_ExtensionObject *eo, + void * UA_RESTRICT p, + const UA_DataType *type) { + UA_ExtensionObject_init(eo); + eo->content.decoded.data = p; + eo->content.decoded.type = type; + eo->encoding = UA_EXTENSIONOBJECT_DECODED; +} + +void +UA_ExtensionObject_setValueNoDelete(UA_ExtensionObject *eo, + void * UA_RESTRICT p, + const UA_DataType *type) { + UA_ExtensionObject_init(eo); + eo->content.decoded.data = p; + eo->content.decoded.type = type; + eo->encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE; +} + +UA_StatusCode +UA_ExtensionObject_setValueCopy(UA_ExtensionObject *eo, + void * UA_RESTRICT p, + const UA_DataType *type) { + UA_ExtensionObject_init(eo); + + /* Make a copy of the value */ + void *val = UA_malloc(type->memSize); + if(UA_UNLIKELY(!val)) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_StatusCode res = UA_copy(p, val, type); + if(UA_UNLIKELY(res != UA_STATUSCODE_GOOD)) { + UA_free(val); + return res; + } + + /* Set the ExtensionObject */ + eo->content.decoded.data = val; + eo->content.decoded.type = type; + eo->encoding = UA_EXTENSIONOBJECT_DECODED; + return UA_STATUSCODE_GOOD; +} + +/* Variant */ +static void +Variant_clear(UA_Variant *p, const UA_DataType *_) { + /* The content is "borrowed" */ + if(p->storageType == UA_VARIANT_DATA_NODELETE) + return; + + /* Delete the value */ + if(p->type && p->data > UA_EMPTY_ARRAY_SENTINEL) { + if(p->arrayLength == 0) + p->arrayLength = 1; + UA_Array_delete(p->data, p->arrayLength, p->type); + p->data = NULL; + } + + /* Delete the array dimensions */ + if((void*)p->arrayDimensions > UA_EMPTY_ARRAY_SENTINEL) + UA_free(p->arrayDimensions); +} + +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 * UA_RESTRICT p, + const UA_DataType *type) { + void *n = UA_malloc(type->memSize); + if(UA_UNLIKELY(!n)) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_StatusCode retval = UA_copy(p, n, type); + if(UA_UNLIKELY(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 * UA_RESTRICT array, + size_t arraySize, const UA_DataType *type) { + UA_Variant_init(v); + UA_StatusCode retval = UA_Array_copy(array, arraySize, &v->data, type); + 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); + + /* Upper bound of the dimensions for stack-allocation */ + if(dims_count > UA_MAX_ARRAY_DIMS) + return UA_STATUSCODE_BADINTERNALERROR; + UA_UInt32 realmax[UA_MAX_ARRAY_DIMS]; + + /* Test the integrity of the range and compute the max index used for every + * dimension. The standard says in Part 4, Section 7.22: + * + * When reading a value, the indexes may not specify a range that is within + * the bounds of the array. The Server shall return a partial result if some + * elements exist within the range. */ + size_t count = 1; + if(range.dimensionsSize != dims_count) + return UA_STATUSCODE_BADINDEXRANGENODATA; + for(size_t i = 0; i < dims_count; ++i) { + if(range.dimensions[i].min > range.dimensions[i].max) + 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; + UA_Boolean 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 UA_Boolean +isStringLike(const UA_DataType *type) { + if(type == &UA_TYPES[UA_TYPES_STRING] || + type == &UA_TYPES[UA_TYPES_BYTESTRING] || + type == &UA_TYPES[UA_TYPES_XMLELEMENT]) + 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 * UA_RESTRICT dst, + const UA_NumericRange range) { + if(!src->type) + return UA_STATUSCODE_BADINVALIDARGUMENT; + UA_Boolean isScalar = UA_Variant_isScalar(src); + UA_Boolean stringLike = isStringLike(src->type); + UA_Variant arraySrc; + + /* 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_clear(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, UA_Boolean 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) { + clearJumpTable[v->type->typeKind]((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 * UA_RESTRICT array, + size_t arraySize, const UA_NumericRange range) { + return Variant_setRange(v, (void*)(uintptr_t)array, + arraySize, range, true); +} + +/* LocalizedText */ +static void +LocalizedText_clear(UA_LocalizedText *p, const UA_DataType *_) { + String_clear(&p->locale, NULL); + String_clear(&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_clear(UA_DataValue *p, const UA_DataType *_) { + Variant_clear(&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_clear(dst, NULL); + return retval; +} + +/* DiagnosticInfo */ +static void +DiagnosticInfo_clear(UA_DiagnosticInfo *p, const UA_DataType *_) { + String_clear(&p->additionalInfo, NULL); + if(p->hasInnerDiagnosticInfo && p->innerDiagnosticInfo) { + DiagnosticInfo_clear(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(UA_LIKELY(dst->innerDiagnosticInfo != NULL)) { + retval |= DiagnosticInfo_copy(src->innerDiagnosticInfo, + dst->innerDiagnosticInfo, NULL); + dst->hasInnerDiagnosticInfo = true; + } else { + dst->hasInnerDiagnosticInfo = false; + retval |= UA_STATUSCODE_BADOUTOFMEMORY; + } + } + return retval; +} + +/* StatusCode */ +UA_Boolean +UA_StatusCode_isBad(const UA_StatusCode code) { + if ((code & 0x80000000) != 0) { + return UA_TRUE; + } + return UA_FALSE; +} + +/********************/ +/* 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; +} + +static UA_StatusCode +copyStructure(const void *src, void *dst, const UA_DataType *type) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + uintptr_t ptrs = (uintptr_t)src; + uintptr_t ptrd = (uintptr_t)dst; + for(size_t i = 0; i < type->membersSize; ++i) { + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + ptrs += m->padding; + ptrd += m->padding; + if(!m->isOptional) { + if(!m->isArray) { + retval |= copyJumpTable[mt->typeKind]((const void *)ptrs, (void *)ptrd, mt); + ptrs += mt->memSize; + ptrd += mt->memSize; + } else { + 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*); + } + } else { + if(!m->isArray) { + if(*(void* const*)ptrs != NULL) + retval |= UA_Array_copy(*(void* const*)ptrs, 1, (void**)ptrd, mt); + } else { + if(*(void* const*)(ptrs+sizeof(size_t)) != NULL) { + size_t *dst_size = (size_t*)ptrd; + const size_t size = *((const size_t*)ptrs); + ptrs += sizeof(size_t); + ptrd += sizeof(size_t); + retval |= UA_Array_copy(*(void* const*)ptrs, size, (void**)ptrd, mt); + if(retval == UA_STATUSCODE_GOOD) + *dst_size = size; + else + *dst_size = 0; + } else { + ptrs += sizeof(size_t); + ptrd += sizeof(size_t); + } + } + ptrs += sizeof(void*); + ptrd += sizeof(void*); + } + } + return retval; +} + +static UA_StatusCode +copyUnion(const void *src, void *dst, const UA_DataType *type) { + uintptr_t ptrs = (uintptr_t) src; + uintptr_t ptrd = (uintptr_t) dst; + UA_UInt32 selection = *(UA_UInt32 *)ptrs; + UA_copy((const UA_UInt32 *) ptrs, (UA_UInt32 *) ptrd, &UA_TYPES[UA_TYPES_UINT32]); + if(selection == 0) + return UA_STATUSCODE_GOOD; + const UA_DataTypeMember *m = &type->members[selection-1]; + const UA_DataType *mt = m->memberType; + ptrs += m->padding; + ptrd += m->padding; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + + if (m->isArray) { + size_t *dst_size = (size_t*)ptrd; + const size_t size = *((const size_t*)ptrs); + ptrs += sizeof(size_t); + ptrd += sizeof(size_t); + retval = UA_Array_copy(*(void* const*)ptrs, size, (void**)ptrd, mt); + if(retval == UA_STATUSCODE_GOOD) + *dst_size = size; + else + *dst_size = 0; + } else { + retval = copyJumpTable[mt->typeKind]((const void *)ptrs, (void *)ptrd, mt); + } + + return retval; +} + +static UA_StatusCode +copyNotImplemented(const void *src, void *dst, const UA_DataType *type) { + return UA_STATUSCODE_BADNOTIMPLEMENTED; +} + +const UA_copySignature copyJumpTable[UA_DATATYPEKINDS] = { + (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)String_copy, + (UA_copySignature)copy8Byte, /* DateTime */ + (UA_copySignature)copyGuid, /* Guid */ + (UA_copySignature)String_copy, /* ByteString */ + (UA_copySignature)String_copy, /* XmlElement */ + (UA_copySignature)NodeId_copy, + (UA_copySignature)ExpandedNodeId_copy, + (UA_copySignature)copy4Byte, /* StatusCode */ + (UA_copySignature)QualifiedName_copy, + (UA_copySignature)LocalizedText_copy, + (UA_copySignature)ExtensionObject_copy, + (UA_copySignature)DataValue_copy, + (UA_copySignature)Variant_copy, + (UA_copySignature)DiagnosticInfo_copy, + (UA_copySignature)copyNotImplemented, /* Decimal */ + (UA_copySignature)copy4Byte, /* Enumeration */ + (UA_copySignature)copyStructure, + (UA_copySignature)copyStructure, /* Structure with Optional Fields */ + (UA_copySignature)copyUnion, /* Union */ + (UA_copySignature)copyNotImplemented /* BitfieldCluster*/ +}; + +UA_StatusCode +UA_copy(const void *src, void *dst, const UA_DataType *type) { + memset(dst, 0, type->memSize); /* init */ + UA_StatusCode retval = copyJumpTable[type->typeKind](src, dst, type); + if(retval != UA_STATUSCODE_GOOD) + UA_clear(dst, type); + return retval; +} + +static void +clearStructure(void *p, const UA_DataType *type) { + uintptr_t ptr = (uintptr_t)p; + for(size_t i = 0; i < type->membersSize; ++i) { + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + ptr += m->padding; + if(!m->isOptional) { + if(!m->isArray) { + clearJumpTable[mt->typeKind]((void*)ptr, mt); + ptr += mt->memSize; + } else { + size_t length = *(size_t*)ptr; + ptr += sizeof(size_t); + UA_Array_delete(*(void**)ptr, length, mt); + ptr += sizeof(void*); + } + } else { /* field is optional */ + if(!m->isArray) { + /* optional scalar field is contained */ + if((*(void *const *)ptr != NULL)) + UA_Array_delete(*(void **)ptr, 1, mt); + ptr += sizeof(void *); + } else { + /* optional array field is contained */ + if((*(void *const *)(ptr + sizeof(size_t)) != NULL)) { + size_t length = *(size_t *)ptr; + ptr += sizeof(size_t); + UA_Array_delete(*(void **)ptr, length, mt); + ptr += sizeof(void *); + } else { /* optional array field not contained */ + ptr += sizeof(size_t); + ptr += sizeof(void *); + } + } + } + } +} + +static void +clearUnion(void *p, const UA_DataType *type) { + uintptr_t ptr = (uintptr_t) p; + UA_UInt32 selection = *(UA_UInt32 *)ptr; + if(selection == 0) + return; + const UA_DataTypeMember *m = &type->members[selection-1]; + const UA_DataType *mt = m->memberType; + ptr += m->padding; + if (m->isArray) { + size_t length = *(size_t *)ptr; + ptr += sizeof(size_t); + UA_Array_delete(*(void **)ptr, length, mt); + } else { + UA_clear((void *) ptr, mt); + } +} + +static void nopClear(void *p, const UA_DataType *type) { } + +const +UA_clearSignature clearJumpTable[UA_DATATYPEKINDS] = { + (UA_clearSignature)nopClear, /* Boolean */ + (UA_clearSignature)nopClear, /* SByte */ + (UA_clearSignature)nopClear, /* Byte */ + (UA_clearSignature)nopClear, /* Int16 */ + (UA_clearSignature)nopClear, /* UInt16 */ + (UA_clearSignature)nopClear, /* Int32 */ + (UA_clearSignature)nopClear, /* UInt32 */ + (UA_clearSignature)nopClear, /* Int64 */ + (UA_clearSignature)nopClear, /* UInt64 */ + (UA_clearSignature)nopClear, /* Float */ + (UA_clearSignature)nopClear, /* Double */ + (UA_clearSignature)String_clear, /* String */ + (UA_clearSignature)nopClear, /* DateTime */ + (UA_clearSignature)nopClear, /* Guid */ + (UA_clearSignature)String_clear, /* ByteString */ + (UA_clearSignature)String_clear, /* XmlElement */ + (UA_clearSignature)NodeId_clear, + (UA_clearSignature)ExpandedNodeId_clear, + (UA_clearSignature)nopClear, /* StatusCode */ + (UA_clearSignature)QualifiedName_clear, + (UA_clearSignature)LocalizedText_clear, + (UA_clearSignature)ExtensionObject_clear, + (UA_clearSignature)DataValue_clear, + (UA_clearSignature)Variant_clear, + (UA_clearSignature)DiagnosticInfo_clear, + (UA_clearSignature)nopClear, /* Decimal, not implemented */ + (UA_clearSignature)nopClear, /* Enumeration */ + (UA_clearSignature)clearStructure, + (UA_clearSignature)clearStructure, /* Struct with Optional Fields*/ + (UA_clearSignature)clearUnion, /* Union*/ + (UA_clearSignature)nopClear /* BitfieldCluster, not implemented*/ +}; + +void +UA_clear(void *p, const UA_DataType *type) { + clearJumpTable[type->typeKind](p, type); + memset(p, 0, type->memSize); /* init */ +} + +void +UA_delete(void *p, const UA_DataType *type) { + clearJumpTable[type->typeKind](p, type); + UA_free(p); +} + +/******************/ +/* Value Ordering */ +/******************/ + +#define UA_NUMERICORDER(NAME, TYPE) \ + static UA_Order \ + NAME(const TYPE *p1, const TYPE *p2, const UA_DataType *type) { \ + if(*p1 != *p2) \ + return (*p1 < *p2) ? UA_ORDER_LESS : UA_ORDER_MORE; \ + return UA_ORDER_EQ; \ + } + +UA_NUMERICORDER(booleanOrder, UA_Boolean) +UA_NUMERICORDER(sByteOrder, UA_SByte) +UA_NUMERICORDER(byteOrder, UA_Byte) +UA_NUMERICORDER(int16Order, UA_Int16) +UA_NUMERICORDER(uInt16Order, UA_UInt16) +UA_NUMERICORDER(int32Order, UA_Int32) +UA_NUMERICORDER(uInt32Order, UA_UInt32) +UA_NUMERICORDER(int64Order, UA_Int64) +UA_NUMERICORDER(uInt64Order, UA_UInt64) + +#define UA_FLOATORDER(NAME, TYPE) \ + static UA_Order \ + NAME(const TYPE *p1, const TYPE *p2, const UA_DataType *type) { \ + if(*p1 != *p2) { \ + /* p1 is NaN */ \ + if(*p1 != *p1) { \ + if(*p2 != *p2) \ + return UA_ORDER_EQ; \ + return UA_ORDER_LESS; \ + } \ + /* p2 is NaN */ \ + if(*p2 != *p2) \ + return UA_ORDER_MORE; \ + return (*p1 < *p2) ? UA_ORDER_LESS : UA_ORDER_MORE; \ + } \ + return UA_ORDER_EQ; \ + } + +UA_FLOATORDER(floatOrder, UA_Float) +UA_FLOATORDER(doubleOrder, UA_Double) + +static UA_Order +guidOrder(const UA_Guid *p1, const UA_Guid *p2, const UA_DataType *type) { + if(p1->data1 != p2->data1) + return (p1->data1 < p2->data1) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->data2 != p2->data2) + return (p1->data2 < p2->data2) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->data3 != p2->data3) + return (p1->data3 < p2->data3) ? UA_ORDER_LESS : UA_ORDER_MORE; + int cmp = memcmp(p1->data4, p2->data4, 8); + if(cmp != 0) + return (cmp < 0) ? UA_ORDER_LESS : UA_ORDER_MORE; + return UA_ORDER_EQ; +} + +static UA_Order +stringOrder(const UA_String *p1, const UA_String *p2, const UA_DataType *type) { + if(p1->length != p2->length) + return (p1->length < p2->length) ? UA_ORDER_LESS : UA_ORDER_MORE; + /* For zero-length arrays, every pointer not NULL is considered a + * UA_EMPTY_ARRAY_SENTINEL. */ + if(p1->data == p2->data) return UA_ORDER_EQ; + if(p1->data == NULL) return UA_ORDER_LESS; + if(p2->data == NULL) return UA_ORDER_MORE; + int cmp = memcmp((const char*)p1->data, (const char*)p2->data, p1->length); + if(cmp != 0) + return (cmp < 0) ? UA_ORDER_LESS : UA_ORDER_MORE; + return UA_ORDER_EQ; +} + +static UA_Order +nodeIdOrder(const UA_NodeId *p1, const UA_NodeId *p2, const UA_DataType *type) { + return UA_NodeId_order(p1, p2); +} + +static UA_Order +expandedNodeIdOrder(const UA_ExpandedNodeId *p1, const UA_ExpandedNodeId *p2, + const UA_DataType *type) { + return UA_ExpandedNodeId_order(p1, p2); +} + +static UA_Order +qualifiedNameOrder(const UA_QualifiedName *p1, const UA_QualifiedName *p2, + const UA_DataType *type) { + if(p1->namespaceIndex != p2->namespaceIndex) + return (p1->namespaceIndex < p2->namespaceIndex) ? UA_ORDER_LESS : UA_ORDER_MORE; + return stringOrder(&p1->name, &p2->name, NULL); +} + +static UA_Order +localizedTextOrder(const UA_LocalizedText *p1, const UA_LocalizedText *p2, + const UA_DataType *type) { + UA_Order o = stringOrder(&p1->locale, &p2->locale, NULL); + if(o != UA_ORDER_EQ) + return o; + return stringOrder(&p1->text, &p2->text, NULL); +} + +static UA_Order +extensionObjectOrder(const UA_ExtensionObject *p1, const UA_ExtensionObject *p2, + const UA_DataType *type) { + UA_ExtensionObjectEncoding enc1 = p1->encoding; + UA_ExtensionObjectEncoding enc2 = p2->encoding; + if(enc1 > UA_EXTENSIONOBJECT_DECODED) + enc1 = UA_EXTENSIONOBJECT_DECODED; + if(enc2 > UA_EXTENSIONOBJECT_DECODED) + enc2 = UA_EXTENSIONOBJECT_DECODED; + if(enc1 != enc2) + return (enc1 < enc2) ? UA_ORDER_LESS : UA_ORDER_MORE; + + switch(enc1) { + case UA_EXTENSIONOBJECT_ENCODED_NOBODY: + return UA_ORDER_EQ; + + case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: + case UA_EXTENSIONOBJECT_ENCODED_XML: { + UA_Order o = UA_NodeId_order(&p1->content.encoded.typeId, + &p2->content.encoded.typeId); + if(o == UA_ORDER_EQ) + o = stringOrder((const UA_String*)&p1->content.encoded.body, + (const UA_String*)&p2->content.encoded.body, NULL); + return o; + } + + case UA_EXTENSIONOBJECT_DECODED: + default: { + const UA_DataType *type1 = p1->content.decoded.type; + const UA_DataType *type2 = p1->content.decoded.type; + if(type1 != type2) + return ((uintptr_t)type1 < (uintptr_t)type2) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(!type1) + return UA_ORDER_EQ; + return orderJumpTable[type1->typeKind] + (p1->content.decoded.data, p2->content.decoded.data, type1); + } + } +} + +static UA_Order +arrayOrder(const void *p1, size_t p1Length, const void *p2, size_t p2Length, + const UA_DataType *type) { + if(p1Length != p2Length) + return (p1Length < p2Length) ? UA_ORDER_LESS : UA_ORDER_MORE; + /* For zero-length arrays, every pointer not NULL is considered a + * UA_EMPTY_ARRAY_SENTINEL. */ + if(p1 == p2) return UA_ORDER_EQ; + if(p1 == NULL) return UA_ORDER_LESS; + if(p2 == NULL) return UA_ORDER_MORE; + uintptr_t u1 = (uintptr_t)p1; + uintptr_t u2 = (uintptr_t)p2; + for(size_t i = 0; i < p1Length; i++) { + UA_Order o = orderJumpTable[type->typeKind]((const void*)u1, (const void*)u2, type); + if(o != UA_ORDER_EQ) + return o; + u1 += type->memSize; + u2 += type->memSize; + } + return UA_ORDER_EQ; +} + +static UA_Order +variantOrder(const UA_Variant *p1, const UA_Variant *p2, + const UA_DataType *type) { + if(p1->type != p2->type) + return ((uintptr_t)p1->type < (uintptr_t)p2->type) ? UA_ORDER_LESS : UA_ORDER_MORE; + + if(p1->arrayLength != p2->arrayLength) + return (p1->arrayLength < p2->arrayLength) ? UA_ORDER_LESS : UA_ORDER_MORE; + + UA_Order o; + if(p1->type != NULL) { + if(p1->arrayLength == 0) + o = orderJumpTable[p1->type->typeKind](p1->data, p2->data, p1->type); + else + o = arrayOrder(p1->data, p1->arrayLength, p2->data, p2->arrayLength, p1->type); + if(o != UA_ORDER_EQ) + return o; + } + + if(p1->arrayDimensionsSize != p2->arrayDimensionsSize) + return (p1->arrayDimensionsSize < p2->arrayDimensionsSize) ? + UA_ORDER_LESS : UA_ORDER_MORE; + o = UA_ORDER_EQ; + if(p1->arrayDimensionsSize > 0) + o = arrayOrder(p1->arrayDimensions, p1->arrayDimensionsSize, + p2->arrayDimensions, p2->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_UINT32]); + return o; +} + +static UA_Order +dataValueOrder(const UA_DataValue *p1, const UA_DataValue *p2, + const UA_DataType *type) { + /* Value */ + if(p1->hasValue != p2->hasValue) + return (!p1->hasValue) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasValue) { + UA_Order o = variantOrder(&p1->value, &p2->value, NULL); + if(o != UA_ORDER_EQ) + return o; + } + + /* Status */ + if(p1->hasStatus != p2->hasStatus) + return (!p1->hasStatus) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasStatus && p1->status != p2->status) + return (p1->status < p2->status) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* SourceTimestamp */ + if(p1->hasSourceTimestamp != p2->hasSourceTimestamp) + return (!p1->hasSourceTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasSourceTimestamp && p1->sourceTimestamp != p2->sourceTimestamp) + return (p1->sourceTimestamp < p2->sourceTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* ServerTimestamp */ + if(p1->hasServerTimestamp != p2->hasServerTimestamp) + return (!p1->hasServerTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasServerTimestamp && p1->serverTimestamp != p2->serverTimestamp) + return (p1->serverTimestamp < p2->serverTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* SourcePicoseconds */ + if(p1->hasSourcePicoseconds != p2->hasSourcePicoseconds) + return (!p1->hasSourcePicoseconds) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasSourcePicoseconds && p1->sourcePicoseconds != p2->sourcePicoseconds) + return (p1->sourcePicoseconds < p2->sourcePicoseconds) ? + UA_ORDER_LESS : UA_ORDER_MORE; + + /* ServerPicoseconds */ + if(p1->hasServerPicoseconds != p2->hasServerPicoseconds) + return (!p1->hasServerPicoseconds) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasServerPicoseconds && p1->serverPicoseconds != p2->serverPicoseconds) + return (p1->serverPicoseconds < p2->serverPicoseconds) ? + UA_ORDER_LESS : UA_ORDER_MORE; + + return UA_ORDER_EQ; +} + +static UA_Order +diagnosticInfoOrder(const UA_DiagnosticInfo *p1, const UA_DiagnosticInfo *p2, + const UA_DataType *type) { + /* SymbolicId */ + if(p1->hasSymbolicId != p2->hasSymbolicId) + return (!p1->hasSymbolicId) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasSymbolicId && p1->symbolicId != p2->symbolicId) + return (p1->symbolicId < p2->symbolicId) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* NamespaceUri */ + if(p1->hasNamespaceUri != p2->hasNamespaceUri) + return (!p1->hasNamespaceUri) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasNamespaceUri && p1->namespaceUri != p2->namespaceUri) + return (p1->namespaceUri < p2->namespaceUri) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* LocalizedText */ + if(p1->hasLocalizedText != p2->hasLocalizedText) + return (!p1->hasLocalizedText) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasLocalizedText && p1->localizedText != p2->localizedText) + return (p1->localizedText < p2->localizedText) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* Locale */ + if(p1->hasLocale != p2->hasLocale) + return (!p1->hasLocale) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasLocale && p1->locale != p2->locale) + return (p1->locale < p2->locale) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* AdditionalInfo */ + if(p1->hasAdditionalInfo != p2->hasAdditionalInfo) + return (!p1->hasAdditionalInfo) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasAdditionalInfo) { + UA_Order o = stringOrder(&p1->additionalInfo, &p2->additionalInfo, NULL); + if(o != UA_ORDER_EQ) + return o; + } + + /* InnerStatusCode */ + if(p1->hasInnerStatusCode != p2->hasInnerStatusCode) + return (!p1->hasInnerStatusCode) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->hasInnerStatusCode && p1->innerStatusCode != p2->innerStatusCode) + return (p1->innerStatusCode < p2->innerStatusCode) ? UA_ORDER_LESS : UA_ORDER_MORE; + + /* InnerDiagnosticInfo */ + if(p1->hasInnerDiagnosticInfo != p2->hasInnerDiagnosticInfo) + return (!p1->hasInnerDiagnosticInfo) ? UA_ORDER_LESS : UA_ORDER_MORE; + if(p1->innerDiagnosticInfo == p2->innerDiagnosticInfo) + return UA_ORDER_EQ; + if(!p1->innerDiagnosticInfo || !p2->innerDiagnosticInfo) + return (!p1->innerDiagnosticInfo) ? UA_ORDER_LESS : UA_ORDER_MORE; + return diagnosticInfoOrder(p1->innerDiagnosticInfo, p2->innerDiagnosticInfo, NULL); +} + +static UA_Order +structureOrder(const void *p1, const void *p2, const UA_DataType *type) { + uintptr_t u1 = (uintptr_t)p1; + uintptr_t u2 = (uintptr_t)p2; + UA_Order o = UA_ORDER_EQ; + for(size_t i = 0; i < type->membersSize; ++i) { + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + u1 += m->padding; + u2 += m->padding; + if(!m->isOptional) { + if(!m->isArray) { + o = orderJumpTable[mt->typeKind]((const void *)u1, (const void *)u2, mt); + u1 += mt->memSize; + u2 += mt->memSize; + } else { + size_t size1 = *(size_t*)u1; + size_t size2 = *(size_t*)u2; + u1 += sizeof(size_t); + u2 += sizeof(size_t); + o = arrayOrder((const void*)u1, size1, (const void*)u2, size2, mt); + u1 += sizeof(void*); + u2 += sizeof(void*); + } + } else { + if(!m->isArray) { + const void *pp1 = *(void* const*)u1; + const void *pp2 = *(void* const*)u2; + if(pp1 == pp2) { + o = UA_ORDER_EQ; + } else if(pp1 == NULL) { + o = UA_ORDER_LESS; + } else if(pp2 == NULL) { + o = UA_ORDER_MORE; + } else { + o = orderJumpTable[mt->typeKind](pp1, pp2, mt); + } + } else { + size_t sa1 = *(size_t*)u1; + size_t sa2 = *(size_t*)u2; + u1 += sizeof(size_t); + u2 += sizeof(size_t); + const void *pa1 = *(void* const*)u1; + const void *pa2 = *(void* const*)u2; + o = arrayOrder(pa1, sa1, pa2, sa2, mt); + } + u1 += sizeof(void*); + u2 += sizeof(void*); + } + + if(o != UA_ORDER_EQ) + break; + } + return o; +} + +static UA_Order +unionOrder(const void *p1, const void *p2, const UA_DataType *type) { + UA_UInt32 sel1 = *(const UA_UInt32 *)p1; + UA_UInt32 sel2 = *(const UA_UInt32 *)p2; + if(sel1 != sel2) + return (sel1 < sel2) ? UA_ORDER_LESS : UA_ORDER_MORE; + + const UA_DataTypeMember *m = &type->members[sel1-1]; + const UA_DataType *mt = m->memberType; + + uintptr_t u1 = ((uintptr_t)p1) + m->padding; /* includes switchfield length */ + uintptr_t u2 = ((uintptr_t)p2) + m->padding; + if(m->isArray) { + size_t sa1 = *(size_t*)u1; + size_t sa2 = *(size_t*)u2; + u1 += sizeof(size_t); + u2 += sizeof(size_t); + return arrayOrder(*(void* const*)u1, sa1, *(void* const*)u2, sa2, mt); + } + return orderJumpTable[mt->typeKind]((const void*)u1, (const void*)u2, mt); +} + +static UA_Order +notImplementedOrder(const void *p1, const void *p2, const UA_DataType *type) { + return UA_ORDER_EQ; +} + +const +UA_orderSignature orderJumpTable[UA_DATATYPEKINDS] = { + (UA_orderSignature)booleanOrder, + (UA_orderSignature)sByteOrder, + (UA_orderSignature)byteOrder, + (UA_orderSignature)int16Order, + (UA_orderSignature)uInt16Order, + (UA_orderSignature)int32Order, + (UA_orderSignature)uInt32Order, + (UA_orderSignature)int64Order, + (UA_orderSignature)uInt64Order, + (UA_orderSignature)floatOrder, + (UA_orderSignature)doubleOrder, + (UA_orderSignature)stringOrder, + (UA_orderSignature)int64Order, /* DateTime */ + (UA_orderSignature)guidOrder, + (UA_orderSignature)stringOrder, /* ByteString */ + (UA_orderSignature)stringOrder, /* XmlElement */ + (UA_orderSignature)nodeIdOrder, + (UA_orderSignature)expandedNodeIdOrder, + (UA_orderSignature)uInt32Order, /* StatusCode */ + (UA_orderSignature)qualifiedNameOrder, + (UA_orderSignature)localizedTextOrder, + (UA_orderSignature)extensionObjectOrder, + (UA_orderSignature)dataValueOrder, + (UA_orderSignature)variantOrder, + (UA_orderSignature)diagnosticInfoOrder, + notImplementedOrder, /* Decimal, not implemented */ + (UA_orderSignature)uInt32Order, /* Enumeration */ + (UA_orderSignature)structureOrder, + (UA_orderSignature)structureOrder, /* Struct with Optional Fields*/ + (UA_orderSignature)unionOrder, /* Union*/ + notImplementedOrder /* BitfieldCluster, not implemented */ +}; + +UA_Order UA_order(const void *p1, const void *p2, const UA_DataType *type) { + return orderJumpTable[type->typeKind](p1, p2, type); +} + +/******************/ +/* Array Handling */ +/******************/ + +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; +} + +UA_StatusCode +UA_Array_resize(void **p, size_t *size, size_t newSize, + const UA_DataType *type) { + if(*size == newSize) + return UA_STATUSCODE_GOOD; + + /* Empty array? */ + if(newSize == 0) { + UA_Array_delete(*p, *size, type); + *p = UA_EMPTY_ARRAY_SENTINEL; + *size = 0; + return UA_STATUSCODE_GOOD; + } + + /* Make a copy of the members that shall be removed. Realloc can fail during + * trimming. So we cannot clear the members already here. */ + void *deleteMembers = NULL; + if(newSize < *size && !type->pointerFree) { + size_t deleteSize = *size - newSize; + deleteMembers = UA_malloc(deleteSize * type->memSize); + if(!deleteMembers) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(deleteMembers, (void*)((uintptr_t)*p + (newSize * type->memSize)), + deleteSize * type->memSize); /* shallow copy */ + } + + void *oldP = *p; + if(oldP == UA_EMPTY_ARRAY_SENTINEL) + oldP = NULL; + + /* Realloc */ + void *newP = UA_realloc(oldP, newSize * type->memSize); + if(!newP) { + if(deleteMembers) + UA_free(deleteMembers); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + /* Clear removed members or initialize the new ones. Note that deleteMembers + * depends on type->pointerFree. */ + if(newSize > *size) + memset((void*)((uintptr_t)newP + (*size * type->memSize)), 0, + (newSize - *size) * type->memSize); + else if(deleteMembers) + UA_Array_delete(deleteMembers, *size - newSize, type); + + /* Set the new array */ + *p = newP; + *size = newSize; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Array_append(void **p, size_t *size, void *newElem, + const UA_DataType *type) { + /* Resize the array */ + size_t oldSize = *size; + UA_StatusCode res = UA_Array_resize(p, size, oldSize+1, type); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Move the value */ + memcpy((void*)((uintptr_t)*p + (oldSize * type->memSize)), + newElem, type->memSize); + UA_init(newElem, type); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode UA_EXPORT +UA_Array_appendCopy(void **p, size_t *size, const void *newElem, + const UA_DataType *type) { + char scratch[512]; + if(type->memSize > 512) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Copy the value */ + UA_StatusCode res = UA_copy(newElem, (void*)scratch, type); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Append */ + res = UA_Array_append(p, size, (void*)scratch, type); + if(res != UA_STATUSCODE_GOOD) + UA_clear((void*)scratch, type); + return res; +} + +void +UA_Array_delete(void *p, size_t size, const UA_DataType *type) { + if(!type->pointerFree) { + uintptr_t ptr = (uintptr_t)p; + for(size_t i = 0; i < size; ++i) { + UA_clear((void*)ptr, type); + ptr += type->memSize; + } + } + UA_free((void*)((uintptr_t)p & ~(uintptr_t)UA_EMPTY_ARRAY_SENTINEL)); +} + +UA_Boolean +UA_DataType_isNumeric(const UA_DataType *type) { + switch(type->typeKind) { + case UA_DATATYPEKIND_SBYTE: + case UA_DATATYPEKIND_BYTE: + case UA_DATATYPEKIND_INT16: + case UA_DATATYPEKIND_UINT16: + case UA_DATATYPEKIND_INT32: + case UA_DATATYPEKIND_UINT32: + case UA_DATATYPEKIND_INT64: + case UA_DATATYPEKIND_UINT64: + case UA_DATATYPEKIND_FLOAT: + case UA_DATATYPEKIND_DOUBLE: + /* not implemented: UA_DATATYPEKIND_DECIMAL */ + return true; + default: + return false; + } +} + +/**********************/ +/* 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_parse(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; +} + +/**** amalgamated original file "/src/ua_types_encoding_binary.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020 (c) Fraunhofer IOSB (Author: Andreas Ebner) + * Copyright 2020 (c) Grigory Friedman + * Copyright 2014-2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2014-2017 (c) Florian Palm + * Copyright 2014-2016 (c) Sten Grüner + * Copyright 2014 (c) Leon Urbas + * 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. + * + * Breaking a message up into chunks is integrated with the encoding. When the + * end of a buffer is reached, a callback is executed that sends the current + * buffer as a chunk and exchanges the encoding buffer "underneath" the ongoing + * encoding. This reduces the RAM requirements and unnecessary copying. */ + +/* Part 6 §5.1.5: Decoders shall support at least 100 nesting levels */ +#define UA_ENCODING_MAX_RECURSION 100 + +typedef struct { + /* Pointers to the current and last buffer position */ + u8 *pos; + const u8 *end; + + /* How often did we en-/decoding recurse? */ + u16 depth; + + const UA_DataTypeArray *customTypes; + 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 *type); + +#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 _clear needs to be called before returning to the + * user. */ +extern const encodeBinarySignature encodeBinaryJumpTable[UA_DATATYPEKINDS]; +extern const decodeBinarySignature decodeBinaryJumpTable[UA_DATATYPEKINDS]; +extern const calcSizeBinarySignature calcSizeBinaryJumpTable[UA_DATATYPEKINDS]; + +/* 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. */ +static status +encodeWithExchangeBuffer(const void *ptr, const UA_DataType *type, Ctx *ctx) { + u8 *oldpos = ctx->pos; /* Last known good position */ +#ifndef NDEBUG + /* We have to ensure that the buffer was not exchanged AND + * BADENCODINGLIMITSEXCEEDED was returned. If that were the case, oldpos + * would be invalid. That means, a type encoding must never return + * BADENCODINGLIMITSEXCEEDED once the buffer could have been exchanged. This + * is achieved by the use of encodeWithExchangeBuffer. */ + const u8 *oldend = ctx->end; + (void)oldend; /* For compilers who don't understand NDEBUG... */ +#endif + status ret = encodeBinaryJumpTable[type->typeKind](ptr, type, ctx); + if(ret == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) { + UA_assert(ctx->end == oldend); + ctx->pos = oldpos; /* Set to the last known good position and exchange */ + ret = exchangeBuffer(ctx); + UA_CHECK_STATUS(ret, return ret); + ret = encodeBinaryJumpTable[type->typeKind](ptr, type, ctx); + } + return ret; +} + +/*****************/ +/* 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 */ +/* Note that sizeof(bool) != 1 on some platforms. Overlayable integer encoding + * is disabled in those cases. */ +ENCODE_BINARY(Boolean) { + UA_CHECK(ctx->pos + 1 <= ctx->end, return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + *ctx->pos = *(const u8*)src; + ++ctx->pos; + return UA_STATUSCODE_GOOD; +} + +DECODE_BINARY(Boolean) { + UA_CHECK(ctx->pos + 1 <= ctx->end, return UA_STATUSCODE_BADDECODINGERROR); + *dst = (*ctx->pos > 0) ? true : false; + ++ctx->pos; + return UA_STATUSCODE_GOOD; +} + +/* Byte */ +ENCODE_BINARY(Byte) { + UA_CHECK(ctx->pos + sizeof(u8) <= ctx->end, + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + *ctx->pos = *(const u8*)src; + ++ctx->pos; + return UA_STATUSCODE_GOOD; +} + +DECODE_BINARY(Byte) { + UA_CHECK(ctx->pos + sizeof(u8) <= ctx->end, + return UA_STATUSCODE_BADDECODINGERROR); + *dst = *ctx->pos; + ++ctx->pos; + return UA_STATUSCODE_GOOD; +} + +/* UInt16 */ +ENCODE_BINARY(UInt16) { + UA_CHECK(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) { + UA_CHECK(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) { + UA_CHECK(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) { + UA_CHECK(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) { + UA_CHECK(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) { + UA_CHECK(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 */ +/************************/ + +/* Can we reuse the integer encoding mechanism by casting floating point + * values? */ +#if (UA_FLOAT_IEEE754 == 1) && (UA_LITTLE_ENDIAN == UA_FLOAT_LITTLE_ENDIAN) +# define Float_encodeBinary UInt32_encodeBinary +# define Float_decodeBinary UInt32_decodeBinary +# define Double_encodeBinary UInt64_encodeBinary +# define Double_decodeBinary UInt64_decodeBinary +#else + +#include + +#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) & (uint64_t)((1LL< 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); + UA_CHECK_STATUS(ret, return ret); + if(decoded == 0) *dst = 0.0; + else if(decoded == DOUBLE_NEG_ZERO) *dst = -0.0; + else if(decoded == DOUBLE_INF) *dst = INFINITY; + 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 memSize, Ctx *ctx) { + /* Loop as long as more elements remain than fit into the chunk */ + while(ctx->end < ctx->pos + memSize) { + size_t possible = ((uintptr_t)ctx->end - (uintptr_t)ctx->pos); + memcpy(ctx->pos, (void*)ptr, possible); + ctx->pos += possible; + ptr += possible; + status ret = exchangeBuffer(ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); + memSize -= possible; + } + + /* Encode the remaining elements */ + memcpy(ctx->pos, (void*)ptr, memSize); + ctx->pos += memSize; + return UA_STATUSCODE_GOOD; +} + +static status +Array_encodeBinaryComplex(uintptr_t ptr, size_t length, + const UA_DataType *type, Ctx *ctx) { + /* Encode every element */ + for(size_t i = 0; i < length; ++i) { + status ret = encodeWithExchangeBuffer((const void*)ptr, type, ctx); + ptr += type->memSize; + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, 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 = encodeWithExchangeBuffer(&signed_length, &UA_TYPES[UA_TYPES_INT32], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); + + /* Encode the content */ + if(length > 0) { + if(type->overlayable) + ret = Array_encodeBinaryOverlayable((uintptr_t)src, length * type->memSize, ctx); + else + ret = Array_encodeBinaryComplex((uintptr_t)src, length, type, ctx); + } + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + return ret; +} + +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 */ + UA_CHECK_STATUS(ret, 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; + UA_CHECK(ctx->pos + ((type->memSize * length) / 32) <= ctx->end, + return UA_STATUSCODE_BADDECODINGERROR); + + /* Allocate memory */ + *dst = UA_calloc(length, type->memSize); + UA_CHECK_MEM(*dst, return UA_STATUSCODE_BADOUTOFMEMORY); + + if(type->overlayable) { + /* memcpy overlayable array */ + UA_CHECK(ctx->pos + (type->memSize * length) <= ctx->end, + UA_free(*dst); *dst = NULL; return UA_STATUSCODE_BADDECODINGERROR); + memcpy(*dst, ctx->pos, type->memSize * length); + ctx->pos += type->memSize * length; + } else { + /* Decode array members */ + uintptr_t ptr = (uintptr_t)*dst; + for(size_t i = 0; i < length; ++i) { + ret = decodeBinaryJumpTable[type->typeKind]((void*)ptr, type, ctx); + UA_CHECK_STATUS(ret, /* +1 because last element is also already initialized */ + UA_Array_delete(*dst, i+1, type); *dst = NULL; return ret); + ptr += type->memSize; + } + } + *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); + UA_CHECK(ctx->pos + (8*sizeof(u8)) <= ctx->end, + return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + memcpy(ctx->pos, src->data4, 8*sizeof(u8)); + ctx->pos += 8; + return ret; +} + +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); + UA_CHECK(ctx->pos + (8*sizeof(u8)) <= ctx->end, + return UA_STATUSCODE_BADDECODINGERROR); + memcpy(dst->data4, ctx->pos, 8*sizeof(u8)); + ctx->pos += 8; + return ret; +} + +/* NodeId */ +#define UA_NODEIDTYPE_NUMERIC_TWOBYTE 0u +#define UA_NODEIDTYPE_NUMERIC_FOURBYTE 1u +#define UA_NODEIDTYPE_NUMERIC_COMPLETE 2u + +#define UA_EXPANDEDNODEID_SERVERINDEX_FLAG 0x40u +#define UA_EXPANDEDNODEID_NAMESPACEURI_FLAG 0x80u + +/* For ExpandedNodeId, we prefill the encoding mask. */ +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 |= (u8)UA_NODEIDTYPE_STRING; + ret |= ENCODE_DIRECT(&encoding, Byte); + ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16); + UA_CHECK_STATUS(ret, return ret); + /* Can exchange the buffer */ + ret = ENCODE_DIRECT(&src->identifier.string, String); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + break; + case UA_NODEIDTYPE_GUID: + encoding |= (u8)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 |= (u8)UA_NODEIDTYPE_BYTESTRING; + ret |= ENCODE_DIRECT(&encoding, Byte); + ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16); + UA_CHECK_STATUS(ret, return ret); + /* Can exchange the buffer */ + ret = ENCODE_DIRECT(&src->identifier.byteString, String); /* ByteString */ + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + break; + 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); + UA_CHECK_STATUS(ret, return ret); + + /* Filter out the bits used only for ExpandedNodeIds */ + encodingByte &= (u8)~(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. Can exchange the buffer. */ + status ret = NodeId_encodeBinaryWithEncodingMask(&src->nodeId, encoding, ctx); + UA_CHECK_STATUS(ret, return ret); + + /* Encode the namespace. Internally uses encodeWithExchangeBuffer + * everywhere. So it will never return + * UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. */ + if((void*)src->namespaceUri.data > UA_EMPTY_ARRAY_SENTINEL) { + ret = ENCODE_DIRECT(&src->namespaceUri, String); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); + } + + /* Encode the serverIndex */ + if(src->serverIndex > 0) + ret = encodeWithExchangeBuffer(&src->serverIndex, &UA_TYPES[UA_TYPES_UINT32], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + return ret; +} + +DECODE_BINARY(ExpandedNodeId) { + /* Decode the encoding mask */ + UA_CHECK(ctx->pos + 1 <= 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; +} + +/* QualifiedName */ +ENCODE_BINARY(QualifiedName) { + status ret = ENCODE_DIRECT(&src->namespaceIndex, UInt16); + /* Must check here so we can exchange the buffer in the string encoding */ + UA_CHECK_STATUS(ret, return ret); + ret |= ENCODE_DIRECT(&src->name, String); + return ret; +} + +DECODE_BINARY(QualifiedName) { + status ret = DECODE_DIRECT(&dst->namespaceIndex, UInt16); + ret |= DECODE_DIRECT(&dst->name, String); + return ret; +} + +/* LocalizedText */ +#define UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE 0x01u +#define UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT 0x02u + +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); + /* Must check here so we can exchange the buffer in the string encoding */ + UA_CHECK_STATUS(ret, return ret); + + /* Encode the strings */ + if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE) + 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) { + /* Always look in the built-in types first. Assume that only numeric + * identifiers are used for the builtin types. (They may contain data types + * from all namespaces though.) */ + if(typeId->identifierType == UA_NODEIDTYPE_NUMERIC) { + for(size_t i = 0; i < UA_TYPES_COUNT; ++i) { + if(UA_TYPES[i].binaryEncodingId.identifier.numeric == typeId->identifier.numeric && + UA_TYPES[i].binaryEncodingId.namespaceIndex == typeId->namespaceIndex) + return &UA_TYPES[i]; + } + } + + const UA_DataTypeArray *customTypes = ctx->customTypes; + while(customTypes) { + for(size_t i = 0; i < customTypes->typesSize; ++i) { + if(UA_NodeId_equal(typeId, &customTypes->types[i].binaryEncodingId)) + return &customTypes->types[i]; + } + customTypes = customTypes->next; + } + + return NULL; +} + +const UA_DataType * +UA_findDataTypeByBinary(const UA_NodeId *typeId) { + Ctx ctx; + ctx.customTypes = NULL; + return UA_findDataTypeByBinaryInternal(typeId, &ctx); +} + +/* ExtensionObject */ +ENCODE_BINARY(ExtensionObject) { + u8 encoding = (u8)src->encoding; + + /* No content or already encoded content. */ + if(encoding <= UA_EXTENSIONOBJECT_ENCODED_XML) { + /* Can exchange the buffer */ + status ret = ENCODE_DIRECT(&src->content.encoded.typeId, NodeId); + UA_CHECK_STATUS(ret, return ret); + ret = encodeWithExchangeBuffer(&encoding, &UA_TYPES[UA_TYPES_BYTE], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); + switch(src->encoding) { + case UA_EXTENSIONOBJECT_ENCODED_NOBODY: + break; + case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: + case UA_EXTENSIONOBJECT_ENCODED_XML: + /* ByteString in disguise. Array encoding can exchange the buffer */ + ret = ENCODE_DIRECT(&src->content.encoded.body, String); + break; + default: + ret = UA_STATUSCODE_BADINTERNALERROR; + } + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + 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. This could perform a buffer + * exchange, but can also return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. */ + status ret = ENCODE_DIRECT(&src->content.decoded.type->binaryEncodingId, NodeId); + UA_CHECK_STATUS(ret, return ret); + + /* Encode the encoding byte */ + encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; + ret = encodeWithExchangeBuffer(&encoding, &UA_TYPES[UA_TYPES_BYTE], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); + + /* Encode the content length */ + const UA_DataType *contentType = src->content.decoded.type; + size_t len = UA_calcSizeBinary(src->content.decoded.data, contentType); + UA_CHECK(len <= UA_INT32_MAX, return UA_STATUSCODE_BADENCODINGERROR); + i32 signed_len = (i32)len; + ret = encodeWithExchangeBuffer(&signed_len, &UA_TYPES[UA_TYPES_INT32], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); + + /* Encode the content */ + ret = encodeWithExchangeBuffer(src->content.decoded.data, contentType, ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + return ret; +} + +static status +ExtensionObject_decodeBinaryContent(UA_ExtensionObject *dst, const UA_NodeId *typeId, + Ctx *ctx) { + /* 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); + UA_CHECK_MEM(dst->content.decoded.data, return UA_STATUSCODE_BADOUTOFMEMORY); + + /* Jump over the length field (TODO: check if the decoded length matches) */ + ctx->pos += 4; + + /* Decode */ + dst->encoding = UA_EXTENSIONOBJECT_DECODED; + dst->content.decoded.type = type; + return decodeBinaryJumpTable[type->typeKind](dst->content.decoded.data, type, ctx); +} + +DECODE_BINARY(ExtensionObject) { + u8 encoding = 0; + UA_NodeId binTypeId; + UA_NodeId_init(&binTypeId); + + status ret = UA_STATUSCODE_GOOD; + ret |= DECODE_DIRECT(&binTypeId, NodeId); + ret |= DECODE_DIRECT(&encoding, Byte); + UA_CHECK_STATUS(ret, UA_NodeId_clear(&binTypeId); return ret); + + switch(encoding) { + case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: + ret = ExtensionObject_decodeBinaryContent(dst, &binTypeId, ctx); + UA_NodeId_clear(&binTypeId); + break; + case UA_EXTENSIONOBJECT_ENCODED_NOBODY: + dst->encoding = (UA_ExtensionObjectEncoding)encoding; + dst->content.encoded.typeId = binTypeId; /* move to dst */ + dst->content.encoded.body = UA_BYTESTRING_NULL; + break; + case 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 */ + UA_CHECK_STATUS(ret, UA_NodeId_clear(&dst->content.encoded.typeId)); + break; + default: + UA_NodeId_clear(&binTypeId); + ret = UA_STATUSCODE_BADDECODINGERROR; + break; + } + + return ret; +} + +/* Variant */ + +static status +Variant_encodeBinaryWrapExtensionObject(const UA_Variant *src, + const UA_Boolean isArray, Ctx *ctx) { + size_t length = 1; /* Default to 1 for a scalar. */ + + /* Encode the array length if required */ + status ret = UA_STATUSCODE_GOOD; + if(isArray) { + UA_CHECK(src->arrayLength <= UA_INT32_MAX, return UA_STATUSCODE_BADENCODINGERROR); + length = src->arrayLength; + i32 encodedLength = (i32)src->arrayLength; + ret = ENCODE_DIRECT(&encodedLength, UInt32); /* Int32 */ + UA_CHECK_STATUS(ret, 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 = encodeWithExchangeBuffer(&eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + ptr += memSize; + } + return ret; +} + +enum UA_VARIANT_ENCODINGMASKTYPE { + UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3Fu, /* bits 0:5 */ + UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS = (u8)(0x01u << 6u), /* bit 6 */ + UA_VARIANT_ENCODINGMASKTYPE_ARRAY = (u8)(0x01u << 7u) /* 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 UA_Boolean isBuiltin = (src->type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO); + const UA_Boolean isEnum = (src->type->typeKind == UA_DATATYPEKIND_ENUM); + if(isBuiltin) + encoding = (u8)(encoding | (u8)((u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(src->type->typeKind + 1u))); + else if(isEnum) + encoding = (u8)(encoding | (u8)((u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(UA_TYPES_INT32 + 1u))); + else + encoding = (u8)(encoding | (u8)((u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(UA_TYPES_EXTENSIONOBJECT + 1u))); + + /* Set the array type in the encoding mask */ + const UA_Boolean isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL; + const UA_Boolean hasDimensions = isArray && src->arrayDimensionsSize > 0; + if(isArray) { + encoding |= (u8)UA_VARIANT_ENCODINGMASKTYPE_ARRAY; + if(hasDimensions) + encoding |= (u8)UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS; + } + + /* Encode the encoding byte */ + status ret = ENCODE_DIRECT(&encoding, Byte); + UA_CHECK_STATUS(ret, return ret); + + /* Encode the content. This can exchange the buffer. */ + if(!isBuiltin && !isEnum) { + /* This could return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. But we + * have not exchanged the buffer so far. */ + ret = Variant_encodeBinaryWrapExtensionObject(src, isArray, ctx); + } else if(!isArray) { + ret = encodeWithExchangeBuffer(src->data, src->type, ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + } else { + ret = Array_encodeBinary(src->data, src->arrayLength, src->type, ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + } + UA_CHECK_STATUS(ret, return ret); + + /* Encode the array dimensions */ + if(hasDimensions && ret == UA_STATUSCODE_GOOD) + ret = Array_encodeBinary(src->arrayDimensions, src->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_INT32], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + 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); + UA_CHECK_STATUS(ret, return ret); + + /* Decode the EncodingByte */ + u8 encoding; + ret = DECODE_DIRECT(&encoding, Byte); + UA_CHECK_STATUS(ret, UA_NodeId_clear(&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_clear(&typeId); + + /* Allocate memory */ + dst->data = UA_new(dst->type); + UA_CHECK_MEM(dst->data, return UA_STATUSCODE_BADOUTOFMEMORY); + + /* Decode the content */ + return decodeBinaryJumpTable[dst->type->typeKind](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); + UA_CHECK_STATUS(ret, 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 UA_Boolean isArray = (encodingByte & (u8)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. The "type kind" + * for types up to DiagnsticInfo equals to the index in the encoding + * byte. */ + size_t typeKind = (size_t)((encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) - 1); + UA_CHECK(typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO, return UA_STATUSCODE_BADDECODINGERROR); + + /* A variant cannot contain a variant. But it can contain an array of + * variants */ + UA_CHECK(typeKind != UA_DATATYPEKIND_VARIANT || isArray, + return UA_STATUSCODE_BADDECODINGERROR); + + /* Check the recursion limit */ + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR); + ctx->depth++; + + /* Decode the content */ + dst->type = &UA_TYPES[typeKind]; + if(isArray) { + ret = Array_decodeBinary(&dst->data, &dst->arrayLength, dst->type, ctx); + } else if(typeKind != UA_DATATYPEKIND_EXTENSIONOBJECT) { + dst->data = UA_new(dst->type); + UA_CHECK_MEM(dst->data, ctx->depth--; return UA_STATUSCODE_BADOUTOFMEMORY); + ret = decodeBinaryJumpTable[typeKind](dst->data, dst->type, ctx); + } else { + ret = Variant_decodeBinaryUnwrapExtensionObject(dst, ctx); + } + + /* Decode array dimensions */ + if(isArray && (encodingByte & (u8)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 = src->hasValue; + encodingMask |= (u8)(src->hasStatus << 1u); + encodingMask |= (u8)(src->hasSourceTimestamp << 2u); + encodingMask |= (u8)(src->hasServerTimestamp << 3u); + encodingMask |= (u8)(src->hasSourcePicoseconds << 4u); + encodingMask |= (u8)(src->hasServerPicoseconds << 5u); + + /* Encode the encoding byte */ + status ret = ENCODE_DIRECT(&encodingMask, Byte); + UA_CHECK_STATUS(ret, return ret); + + /* Encode the variant. */ + if(src->hasValue) { + ret = ENCODE_DIRECT(&src->value, Variant); + if(ret != UA_STATUSCODE_GOOD) + return ret; + } + + if(src->hasStatus) + ret |= encodeWithExchangeBuffer(&src->status, &UA_TYPES[UA_TYPES_STATUSCODE], ctx); + if(src->hasSourceTimestamp) + ret |= encodeWithExchangeBuffer(&src->sourceTimestamp, &UA_TYPES[UA_TYPES_DATETIME], ctx); + if(src->hasSourcePicoseconds) + ret |= encodeWithExchangeBuffer(&src->sourcePicoseconds, &UA_TYPES[UA_TYPES_UINT16], ctx); + if(src->hasServerTimestamp) + ret |= encodeWithExchangeBuffer(&src->serverTimestamp, &UA_TYPES[UA_TYPES_DATETIME], ctx); + if(src->hasServerPicoseconds) + ret |= encodeWithExchangeBuffer(&src->serverPicoseconds, &UA_TYPES[UA_TYPES_UINT16], ctx); + 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); + UA_CHECK_STATUS(ret, return ret); + + /* Check the recursion limit */ + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR); + ctx->depth++; + + /* Decode the content */ + if(encodingMask & 0x01u) { + dst->hasValue = true; + ret |= DECODE_DIRECT(&dst->value, Variant); + } + if(encodingMask & 0x02u) { + dst->hasStatus = true; + ret |= DECODE_DIRECT(&dst->status, UInt32); /* StatusCode */ + } + if(encodingMask & 0x04u) { + dst->hasSourceTimestamp = true; + ret |= DECODE_DIRECT(&dst->sourceTimestamp, UInt64); /* DateTime */ + } + if(encodingMask & 0x10u) { + dst->hasSourcePicoseconds = true; + ret |= DECODE_DIRECT(&dst->sourcePicoseconds, UInt16); + if(dst->sourcePicoseconds > MAX_PICO_SECONDS) + dst->sourcePicoseconds = MAX_PICO_SECONDS; + } + if(encodingMask & 0x08u) { + dst->hasServerTimestamp = true; + ret |= DECODE_DIRECT(&dst->serverTimestamp, UInt64); /* DateTime */ + } + if(encodingMask & 0x20u) { + 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 = src->hasSymbolicId; + encodingMask |= (u8)(src->hasNamespaceUri << 1u); + encodingMask |= (u8)(src->hasLocalizedText << 2u); + encodingMask |= (u8)(src->hasLocale << 3u); + encodingMask |= (u8)(src->hasAdditionalInfo << 4u); + encodingMask |= (u8)(src->hasInnerStatusCode << 5u); + encodingMask |= (u8)(src->hasInnerDiagnosticInfo << 6u); + + /* 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. Can exchange the buffer. */ + if(src->hasAdditionalInfo) { + ret = ENCODE_DIRECT(&src->additionalInfo, String); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); + } + + /* Encode the inner status code */ + if(src->hasInnerStatusCode) { + ret = encodeWithExchangeBuffer(&src->innerStatusCode, &UA_TYPES[UA_TYPES_UINT32], ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + UA_CHECK_STATUS(ret, return ret); + } + + /* Encode the inner diagnostic info */ + if(src->hasInnerDiagnosticInfo) { + ret = encodeWithExchangeBuffer(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); + UA_CHECK_STATUS(ret, return ret); + + /* Decode the content */ + if(encodingMask & 0x01u) { + dst->hasSymbolicId = true; + ret |= DECODE_DIRECT(&dst->symbolicId, UInt32); /* Int32 */ + } + if(encodingMask & 0x02u) { + dst->hasNamespaceUri = true; + ret |= DECODE_DIRECT(&dst->namespaceUri, UInt32); /* Int32 */ + } + if(encodingMask & 0x04u) { + dst->hasLocalizedText = true; + ret |= DECODE_DIRECT(&dst->localizedText, UInt32); /* Int32 */ + } + if(encodingMask & 0x08u) { + dst->hasLocale = true; + ret |= DECODE_DIRECT(&dst->locale, UInt32); /* Int32 */ + } + if(encodingMask & 0x10u) { + dst->hasAdditionalInfo = true; + ret |= DECODE_DIRECT(&dst->additionalInfo, String); + } + if(encodingMask & 0x20u) { + dst->hasInnerStatusCode = true; + ret |= DECODE_DIRECT(&dst->innerStatusCode, UInt32); /* StatusCode */ + } + if(encodingMask & 0x40u) { + /* innerDiagnosticInfo is allocated on the heap */ + dst->innerDiagnosticInfo = (UA_DiagnosticInfo*) + UA_calloc(1, sizeof(UA_DiagnosticInfo)); + UA_CHECK_MEM(dst->innerDiagnosticInfo, return UA_STATUSCODE_BADOUTOFMEMORY); + dst->hasInnerDiagnosticInfo = true; + + /* Check the recursion limit */ + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); + + ctx->depth++; + ret |= DECODE_DIRECT(dst->innerDiagnosticInfo, DiagnosticInfo); + ctx->depth--; + } + return ret; +} + +/********************/ +/* Structured Types */ +/********************/ + +static status +encodeBinaryStruct(const void *src, const UA_DataType *type, Ctx *ctx) { + /* Check the recursion limit */ + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); + ctx->depth++; + + /* Loop over members */ + uintptr_t ptr = (uintptr_t)src; + status ret = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < type->membersSize && ret == UA_STATUSCODE_GOOD; ++i) { + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + ptr += m->padding; + + /* Array. Buffer-exchange is done inside Array_encodeBinary if required. */ + if(m->isArray) { + const size_t length = *((const size_t*)ptr); + ptr += sizeof(size_t); + ret = Array_encodeBinary(*(void *UA_RESTRICT const *)ptr, length, mt, ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + ptr += sizeof(void*); + continue; + } + + /* Scalar */ + ret = encodeWithExchangeBuffer((const void*)ptr, mt, ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + ptr += mt->memSize; + } + + ctx->depth--; + return ret; +} + +static status +encodeBinaryStructWithOptFields(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++; + + /* Creating the encoding mask, marking the available optional fields */ + uintptr_t ptr = (uintptr_t)src; + size_t optFieldCounter = 0; + UA_UInt32 encodingMask = 0; + for(size_t j = 0; j < type->membersSize; ++j) { + const UA_DataTypeMember *m = &type->members[j]; + const UA_DataType *mt = m->memberType; + ptr += m->padding; + if(m->isOptional) { + if(m->isArray) + ptr += sizeof(size_t); + if(*(void* const*)ptr != NULL) + encodingMask |= (UA_UInt32) 1 << optFieldCounter; + ptr += sizeof(void *); + optFieldCounter++; + } else { + if(m->isArray) + ptr += sizeof(size_t); + ptr += mt->memSize; + } + } + + /* Encode the mask */ + status ret = ENCODE_DIRECT(&encodingMask, UInt32); + UA_CHECK_STATUS(ret, ctx->depth--; return ret); + + /* Loop over members */ + ptr = (uintptr_t)src; + for(size_t i = 0, o = 0; i < type->membersSize && UA_LIKELY(ret == UA_STATUSCODE_GOOD); ++i) { + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + ptr += m->padding; + + if(m->isOptional) { + if(!(encodingMask & (UA_UInt32) ( (UA_UInt32) 1<<(o++)))) { + /* Optional and not contained */ + if(m->isArray) + ptr += sizeof(size_t); + } else if(m->isArray) { + /* Optional Array */ + const size_t length = *((const size_t *) ptr); + ptr += sizeof(size_t); + ret = Array_encodeBinary(*(void *UA_RESTRICT const *) ptr, length, mt, ctx); + } else { + /* Optional Scalar */ + ret = encodeWithExchangeBuffer(*(void* const*) ptr, mt, ctx); + } + ptr += sizeof(void *); + continue; + } + + /* Mandatory Array */ + if(m->isArray) { + const size_t length = *((const size_t *) ptr); + ptr += sizeof(size_t); + ret = Array_encodeBinary(*(void *UA_RESTRICT const *) ptr, length, mt, ctx); + ptr += sizeof(void *); + continue; + } + + /* Mandatory Scalar */ + ret = encodeWithExchangeBuffer((const void*)ptr, mt, ctx); + ptr += mt->memSize; + } + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + + ctx->depth--; + return ret; +} + +static status +encodeBinaryUnion(const void *src, const UA_DataType *type, Ctx *ctx) { + /* Check the recursion limit */ + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); + ctx->depth++; + + /* Encode the selection */ + const UA_UInt32 selection = *(const UA_UInt32*)src; + status ret = ENCODE_DIRECT(&selection, UInt32); + if(UA_UNLIKELY(ret != UA_STATUSCODE_GOOD) || selection == 0) { + ctx->depth--; + return ret; + } + + /* Select the member */ + const UA_DataTypeMember *m = &type->members[selection-1]; + const UA_DataType *mt = m->memberType; + + /* Encode the member */ + uintptr_t ptr = ((uintptr_t)src) + m->padding; /* includes the switchfield length */ + if(!m->isArray) { + ret = encodeWithExchangeBuffer((const void*)ptr, mt, ctx); + } else { + const size_t length = *((const size_t*)ptr); + ptr += sizeof(size_t); + ret = Array_encodeBinary(*(void *UA_RESTRICT const *)ptr, length, mt, ctx); + } + + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + + ctx->depth--; + return ret; +} + +static status +encodeBinaryNotImplemented(const void *src, const UA_DataType *type, Ctx *ctx) { + (void)src, (void)type, (void)ctx; + return UA_STATUSCODE_BADNOTIMPLEMENTED; +} + +const encodeBinarySignature encodeBinaryJumpTable[UA_DATATYPEKINDS] = { + (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)QualifiedName_encodeBinary, + (encodeBinarySignature)LocalizedText_encodeBinary, + (encodeBinarySignature)ExtensionObject_encodeBinary, + (encodeBinarySignature)DataValue_encodeBinary, + (encodeBinarySignature)Variant_encodeBinary, + (encodeBinarySignature)DiagnosticInfo_encodeBinary, + (encodeBinarySignature)encodeBinaryNotImplemented, /* Decimal */ + (encodeBinarySignature)UInt32_encodeBinary, /* Enumeration */ + (encodeBinarySignature)encodeBinaryStruct, + (encodeBinarySignature)encodeBinaryStructWithOptFields, /* Structure with Optional Fields */ + (encodeBinarySignature)encodeBinaryUnion, /* Union */ + (encodeBinarySignature)encodeBinaryStruct /* BitfieldCluster */ +}; + +status +UA_encodeBinaryInternal(const void *src, const UA_DataType *type, + u8 **bufPos, const u8 **bufEnd, + UA_exchangeEncodeBuffer exchangeCallback, + void *exchangeHandle) { + /* Set up the context */ + Ctx ctx; + ctx.pos = *bufPos; + ctx.end = *bufEnd; + ctx.depth = 0; + ctx.exchangeBufferCallback = exchangeCallback; + ctx.exchangeBufferCallbackHandle = exchangeHandle; + + UA_CHECK_MEM(ctx.pos, return UA_STATUSCODE_BADINVALIDARGUMENT); + + /* Encode */ + status ret = encodeWithExchangeBuffer(src, type, &ctx); + UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED); + + /* 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; +} + +UA_StatusCode +UA_encodeBinary(const void *p, const UA_DataType *type, + UA_ByteString *outBuf) { + /* Allocate buffer */ + UA_Boolean allocated = false; + status res = UA_STATUSCODE_GOOD; + if(outBuf->length == 0) { + size_t len = UA_calcSizeBinary(p, type); + res = UA_ByteString_allocBuffer(outBuf, len); + if(res != UA_STATUSCODE_GOOD) + return res; + allocated = true; + } + + /* Encode */ + u8 *pos = outBuf->data; + const u8 *posEnd = &outBuf->data[outBuf->length]; + res = UA_encodeBinaryInternal(p, type, &pos, &posEnd, NULL, NULL); + + /* Clean up */ + if(res == UA_STATUSCODE_GOOD) { + outBuf->length = (size_t)((uintptr_t)pos - (uintptr_t)outBuf->data); + } else if(allocated) { + UA_ByteString_clear(outBuf); + } + return res; +} + +static status +decodeBinaryNotImplemented(void *dst, const UA_DataType *type, Ctx *ctx) { + (void)dst, (void)type, (void)ctx; + return UA_STATUSCODE_BADNOTIMPLEMENTED; +} + +static status +decodeBinaryStructure(void *dst, const UA_DataType *type, Ctx *ctx) { + /* Check the recursion limit */ + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); + ctx->depth++; + + uintptr_t ptr = (uintptr_t)dst; + status ret = UA_STATUSCODE_GOOD; + u8 membersSize = type->membersSize; + + /* Loop over members */ + for(size_t i = 0; i < membersSize && ret == UA_STATUSCODE_GOOD; ++i) { + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + ptr += m->padding; + + /* Array */ + if(m->isArray) { + size_t *length = (size_t*)ptr; + ptr += sizeof(size_t); + ret = Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt , ctx); + ptr += sizeof(void*); + continue; + } + + /* Scalar */ + ret = decodeBinaryJumpTable[mt->typeKind]((void *UA_RESTRICT)ptr, mt, ctx); + ptr += mt->memSize; + } + + ctx->depth--; + return ret; +} + +static status +decodeBinaryStructureWithOptFields(void *dst, const UA_DataType *type, Ctx *ctx) { + /* Check the recursion limit */ + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR); + ctx->depth++; + + uintptr_t ptr = (uintptr_t)dst; + UA_UInt32 encodingMask = 0; + status ret = UInt32_decodeBinary(&encodingMask, &UA_TYPES[UA_TYPES_UINT32], ctx); + UA_CHECK_STATUS(ret, ctx->depth--; return ret); + + /* Loop over members */ + for(size_t i = 0, o = 0; i < type->membersSize && ret == UA_STATUSCODE_GOOD; ++i) { + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + ptr += m->padding; + if(m->isOptional) { + if(!(encodingMask & (UA_UInt32) ( (UA_UInt32) 1<<(o++)))) { + /* Optional field is not contained */ + if(m->isArray) + ptr += sizeof(size_t); + } else if(m->isArray) { + /* Optional Array */ + size_t *length = (size_t*)ptr; + ptr += sizeof(size_t); + ret = Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt , ctx); + } else { + /* Optional Scalar */ + *(void *UA_RESTRICT *UA_RESTRICT) ptr = UA_calloc(1, mt->memSize); + UA_CHECK_MEM(*(void *UA_RESTRICT *UA_RESTRICT) ptr, return UA_STATUSCODE_BADOUTOFMEMORY); + ret = decodeBinaryJumpTable[mt->typeKind](*(void *UA_RESTRICT *UA_RESTRICT) ptr, mt, ctx); + } + ptr += sizeof(void *); + continue; + } + + /* Array */ + if(m->isArray) { + size_t *length = (size_t *)ptr; + ptr += sizeof(size_t); + ret = Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt, ctx); + ptr += sizeof(void *); + continue; + } + + /* Scalar */ + ret = decodeBinaryJumpTable[mt->typeKind]((void *UA_RESTRICT)ptr, mt, ctx); + ptr += mt->memSize; + } + ctx->depth--; + return ret; +} + +static status +decodeBinaryUnion(void *UA_RESTRICT dst, const UA_DataType *type, Ctx *ctx) { + /* Check the recursion limit */ + UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, + return UA_STATUSCODE_BADENCODINGERROR); + + /* Decode the selection directly into the switchfield */ + status ret = DECODE_DIRECT(dst, UInt32); + UA_CHECK_STATUS(ret, return ret); + + /* No content? */ + UA_UInt32 selection = *(UA_UInt32*)dst; + if(selection == 0) + return UA_STATUSCODE_GOOD; + + /* Sanity check the selection */ + UA_CHECK(selection-1 < type->membersSize, + return UA_STATUSCODE_BADDECODINGERROR); + + /* Select the member */ + const UA_DataTypeMember *m = &type->members[selection-1]; + const UA_DataType *mt = m->memberType; + + /* Decode */ + ctx->depth++; + uintptr_t ptr = ((uintptr_t)dst) + m->padding; /* includes the switchfield */ + if(!m->isArray) { + ret = decodeBinaryJumpTable[mt->typeKind]((void *UA_RESTRICT)ptr, mt, ctx); + } else { + size_t *length = (size_t *)ptr; + ptr += sizeof(size_t); + ret = Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt, ctx); + } + ctx->depth--; + return ret; +} + +const decodeBinarySignature decodeBinaryJumpTable[UA_DATATYPEKINDS] = { + (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)QualifiedName_decodeBinary, + (decodeBinarySignature)LocalizedText_decodeBinary, + (decodeBinarySignature)ExtensionObject_decodeBinary, + (decodeBinarySignature)DataValue_decodeBinary, + (decodeBinarySignature)Variant_decodeBinary, + (decodeBinarySignature)DiagnosticInfo_decodeBinary, + (decodeBinarySignature)decodeBinaryNotImplemented, /* Decimal */ + (decodeBinarySignature)UInt32_decodeBinary, /* Enumeration */ + (decodeBinarySignature)decodeBinaryStructure, + (decodeBinarySignature)decodeBinaryStructureWithOptFields, /* Structure with optional fields */ + (decodeBinarySignature)decodeBinaryUnion, /* Union */ + (decodeBinarySignature)decodeBinaryNotImplemented /* BitfieldCluster */ +}; + +status +UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset, + void *dst, const UA_DataType *type, + const UA_DataTypeArray *customTypes) { + /* Set up the context */ + Ctx ctx; + ctx.pos = &src->data[*offset]; + ctx.end = &src->data[src->length]; + ctx.depth = 0; + ctx.customTypes = customTypes; + + /* Decode */ + memset(dst, 0, type->memSize); /* Initialize the value */ + status ret = decodeBinaryJumpTable[type->typeKind](dst, type, &ctx); + + if(UA_LIKELY(ret == UA_STATUSCODE_GOOD)) { + /* Set the new offset */ + *offset = (size_t)(ctx.pos - src->data) / sizeof(u8); + } else { + /* Clean up */ + UA_clear(dst, type); + memset(dst, 0, type->memSize); + } + return ret; +} + +UA_StatusCode +UA_decodeBinary(const UA_ByteString *inBuf, + void *p, const UA_DataType *type, + const UA_DecodeBinaryOptions *options) { + size_t offset = 0; + const UA_DataTypeArray *customTypes = options ? options->customTypes : NULL; + return UA_decodeBinaryInternal(inBuf, &offset, p, type, customTypes); +} + +/** + * Compute the Message Size + * ------------------------ + * 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; + for(size_t i = 0; i < length; ++i) { + s += calcSizeBinaryJumpTable[type->typeKind]((const void*)ptr, type); + ptr += type->memSize; + } + return s; +} + +static size_t calcSizeBinary1(const void *_, const UA_DataType *__) { (void)_, (void)__; return 1; } +static size_t calcSizeBinary2(const void *_, const UA_DataType *__) { (void)_, (void)__; return 2; } +static size_t calcSizeBinary4(const void *_, const UA_DataType *__) { (void)_, (void)__; return 4; } +static size_t calcSizeBinary8(const void *_, const UA_DataType *__) { (void)_, (void)__; return 8; } + +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(QualifiedName) { + return 2 + String_calcSizeBinary(&src->name, NULL); +} + +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 */ + + /* Encoded content */ + if(src->encoding <= UA_EXTENSIONOBJECT_ENCODED_XML) { + 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; + } + + /* Decoded content */ + 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->binaryEncodingId, NULL); /* Type encoding length */ + s += 4; /* Encoding length field */ + const UA_DataType *type = src->content.decoded.type; + s += calcSizeBinaryJumpTable[type->typeKind](src->content.decoded.data, type); /* Encoding length */ + return s; +} + +CALCSIZE_BINARY(Variant) { + size_t s = 1; /* Encoding byte */ + if(!src->type) + return s; + + const UA_Boolean isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL; + if(isArray) + s += Array_calcSizeBinary(src->data, src->arrayLength, src->type); + else + s += calcSizeBinaryJumpTable[src->type->typeKind](src->data, src->type); + + const UA_Boolean isBuiltin = (src->type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO); + const UA_Boolean isEnum = (src->type->typeKind == UA_DATATYPEKIND_ENUM); + if(!isBuiltin && !isEnum) { + /* The type is wrapped inside an extensionobject */ + /* (NodeId + encoding byte + extension object length) * array length */ + size_t length = isArray ? src->arrayLength : 1; + s += (NodeId_calcSizeBinary(&src->type->binaryEncodingId, NULL) + 1 + 4) * length; + } + + const UA_Boolean hasDimensions = isArray && src->arrayDimensionsSize > 0; + 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; +} + +static size_t +calcSizeBinaryStructure(const void *p, const UA_DataType *type) { + size_t s = 0; + uintptr_t ptr = (uintptr_t)p; + u8 membersSize = type->membersSize; + + /* Loop over members */ + for(size_t i = 0; i < membersSize; ++i) { + const UA_DataTypeMember *member = &type->members[i]; + const UA_DataType *membertype = member->memberType; + ptr += member->padding; + + /* Array */ + if(member->isArray) { + 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*); + continue; + } + + /* Scalar */ + s += calcSizeBinaryJumpTable[membertype->typeKind]((const void*)ptr, membertype); + ptr += membertype->memSize; + } + + return s; +} + +static size_t +calcSizeBinaryStructureWithOptFields(const void *p, const UA_DataType *type) { + /* Start with the size of the encoding mask */ + size_t s = sizeof(UA_UInt32); + + /* Loop over members */ + uintptr_t ptr = (uintptr_t)p; + for(size_t i = 0; i < type->membersSize; ++i) { + const UA_DataTypeMember *member = &type->members[i]; + const UA_DataType *membertype = member->memberType; + ptr += member->padding; + if(member->isOptional) { + if((member->isArray && ((*(void* const*)(ptr+sizeof(size_t))) == NULL)) || + (!member->isArray && (*(void* const*)ptr == NULL))) { + /* Optional member not contained */ + if(member->isArray) + ptr += sizeof(size_t); + ptr += sizeof(void *); + continue; + } + /* Fallthrough to take the size into account */ + } + /* Array */ + if(member->isArray) { + 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*); + continue; + } + /* Scalar */ + s += calcSizeBinaryJumpTable[membertype->typeKind]((const void*)ptr, membertype); + member->isOptional ? (ptr += sizeof(void *)) : (ptr += membertype->memSize); + } + return s; +} + +static size_t +calcSizeBinaryUnion(const void *p, const UA_DataType *type) { + size_t s = 4; /* UA_TYPES[UA_TYPES_UINT32].memSize; */ + const UA_UInt32 selection = *(const UA_UInt32 *)p; + if(selection == 0) + return s; + + const UA_DataTypeMember *m = &type->members[selection-1]; + const UA_DataType *mt = m->memberType; + + uintptr_t ptr = ((uintptr_t)p) + m->padding; /* includes switchfield length */ + if(!m->isArray) { + s += UA_calcSizeBinary((const void*)ptr, mt); + } else { + const size_t length = *((const size_t*)ptr); + ptr += sizeof(size_t); + s += Array_calcSizeBinary(*(void *UA_RESTRICT const *)ptr, length, mt); + } + return s; +} + +static size_t +calcSizeBinaryNotImplemented(const void *p, const UA_DataType *type) { + (void)p, (void)type; + return 0; +} + +const calcSizeBinarySignature calcSizeBinaryJumpTable[UA_DATATYPEKINDS] = { + (calcSizeBinarySignature)calcSizeBinary1, /* Boolean */ + (calcSizeBinarySignature)calcSizeBinary1, /* SByte */ + (calcSizeBinarySignature)calcSizeBinary1, /* Byte */ + (calcSizeBinarySignature)calcSizeBinary2, /* Int16 */ + (calcSizeBinarySignature)calcSizeBinary2, /* UInt16 */ + (calcSizeBinarySignature)calcSizeBinary4, /* Int32 */ + (calcSizeBinarySignature)calcSizeBinary4, /* UInt32 */ + (calcSizeBinarySignature)calcSizeBinary8, /* Int64 */ + (calcSizeBinarySignature)calcSizeBinary8, /* UInt64 */ + (calcSizeBinarySignature)calcSizeBinary4, /* Float */ + (calcSizeBinarySignature)calcSizeBinary8, /* Double */ + (calcSizeBinarySignature)String_calcSizeBinary, + (calcSizeBinarySignature)calcSizeBinary8, /* DateTime */ + (calcSizeBinarySignature)Guid_calcSizeBinary, + (calcSizeBinarySignature)String_calcSizeBinary, /* ByteString */ + (calcSizeBinarySignature)String_calcSizeBinary, /* XmlElement */ + (calcSizeBinarySignature)NodeId_calcSizeBinary, + (calcSizeBinarySignature)ExpandedNodeId_calcSizeBinary, + (calcSizeBinarySignature)calcSizeBinary4, /* StatusCode */ + (calcSizeBinarySignature)QualifiedName_calcSizeBinary, + (calcSizeBinarySignature)LocalizedText_calcSizeBinary, + (calcSizeBinarySignature)ExtensionObject_calcSizeBinary, + (calcSizeBinarySignature)DataValue_calcSizeBinary, + (calcSizeBinarySignature)Variant_calcSizeBinary, + (calcSizeBinarySignature)DiagnosticInfo_calcSizeBinary, + (calcSizeBinarySignature)calcSizeBinaryNotImplemented, /* Decimal */ + (calcSizeBinarySignature)calcSizeBinary4, /* Enumeration */ + (calcSizeBinarySignature)calcSizeBinaryStructure, + (calcSizeBinarySignature)calcSizeBinaryStructureWithOptFields, /* Structure with Optional Fields */ + (calcSizeBinarySignature)calcSizeBinaryUnion, /* Union */ + (calcSizeBinarySignature)calcSizeBinaryNotImplemented /* BitfieldCluster */ +}; + +size_t +UA_calcSizeBinary(const void *p, const UA_DataType *type) { + return calcSizeBinaryJumpTable[type->typeKind](p, type); +} + +/**** amalgamated original file "/src/ua_types_print.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + */ + + + +/* Printing of NodeIds is always enabled. We need it for logging. */ + +UA_StatusCode +UA_NodeId_print(const UA_NodeId *id, UA_String *output) { + UA_String_clear(output); + if(!id) + return UA_STATUSCODE_GOOD; + + char *nsStr = NULL; + long snprintfLen = 0; + size_t nsLen = 0; + if(id->namespaceIndex != 0) { + nsStr = (char*)UA_malloc(9+1); // strlen("ns=XXXXX;") = 9 + Nullbyte + if(!nsStr) + return UA_STATUSCODE_BADOUTOFMEMORY; + snprintfLen = UA_snprintf(nsStr, 10, "ns=%d;", id->namespaceIndex); + if(snprintfLen < 0 || snprintfLen >= 10) { + UA_free(nsStr); + return UA_STATUSCODE_BADINTERNALERROR; + } + nsLen = (size_t)(snprintfLen); + } + + UA_ByteString byteStr = UA_BYTESTRING_NULL; + switch (id->identifierType) { + case UA_NODEIDTYPE_NUMERIC: + /* ns (2 byte, 65535) = 5 chars, numeric (4 byte, 4294967295) = 10 + * chars, delim = 1 , nullbyte = 1-> 17 chars */ + output->length = nsLen + 2 + 10 + 1; + output->data = (UA_Byte*)UA_malloc(output->length); + if(output->data == NULL) { + output->length = 0; + UA_free(nsStr); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + snprintfLen = UA_snprintf((char*)output->data, output->length, "%si=%lu", + nsLen > 0 ? nsStr : "", + (unsigned long )id->identifier.numeric); + break; + case UA_NODEIDTYPE_STRING: + /* ns (16bit) = 5 chars, strlen + nullbyte */ + output->length = nsLen + 2 + id->identifier.string.length + 1; + output->data = (UA_Byte*)UA_malloc(output->length); + if(output->data == NULL) { + output->length = 0; + UA_free(nsStr); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + snprintfLen = UA_snprintf((char*)output->data, output->length, "%ss=%.*s", + nsLen > 0 ? nsStr : "", (int)id->identifier.string.length, + id->identifier.string.data); + break; + case UA_NODEIDTYPE_GUID: + /* ns (16bit) = 5 chars + strlen(A123456C-0ABC-1A2B-815F-687212AAEE1B)=36 + nullbyte */ + output->length = nsLen + 2 + 36 + 1; + output->data = (UA_Byte*)UA_malloc(output->length); + if(output->data == NULL) { + output->length = 0; + UA_free(nsStr); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + snprintfLen = UA_snprintf((char*)output->data, output->length, + "%sg=" UA_PRINTF_GUID_FORMAT, nsLen > 0 ? nsStr : "", + UA_PRINTF_GUID_DATA(id->identifier.guid)); + break; + case UA_NODEIDTYPE_BYTESTRING: + UA_ByteString_toBase64(&id->identifier.byteString, &byteStr); + /* ns (16bit) = 5 chars + LEN + nullbyte */ + output->length = nsLen + 2 + byteStr.length + 1; + output->data = (UA_Byte*)UA_malloc(output->length); + if(output->data == NULL) { + output->length = 0; + UA_String_clear(&byteStr); + UA_free(nsStr); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + snprintfLen = UA_snprintf((char*)output->data, output->length, "%sb=%.*s", + nsLen > 0 ? nsStr : "", + (int)byteStr.length, byteStr.data); + UA_String_clear(&byteStr); + break; + } + UA_free(nsStr); + + if(snprintfLen < 0 || snprintfLen >= (long) output->length) { + UA_free(output->data); + output->data = NULL; + output->length = 0; + return UA_STATUSCODE_BADINTERNALERROR; + } + output->length = (size_t)snprintfLen; + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_ExpandedNodeId_print(const UA_ExpandedNodeId *id, UA_String *output) { + /* Don't print the namespace-index if a NamespaceUri is set */ + UA_NodeId nid = id->nodeId; + if(id->namespaceUri.data != NULL) + nid.namespaceIndex = 0; + + /* Encode the NodeId */ + UA_String outNid = UA_STRING_NULL; + UA_StatusCode res = UA_NodeId_print(&nid, &outNid); + if(res != UA_STATUSCODE_GOOD) + return res; + + /* Encode the ServerIndex */ + char svr[100]; + if(id->serverIndex == 0) + svr[0] = 0; + else + UA_snprintf(svr, 100, "svr=%"PRIu32";", id->serverIndex); + size_t svrlen = strlen(svr); + + /* Encode the NamespaceUri */ + char nsu[100]; + if(id->namespaceUri.data == NULL) + nsu[0] = 0; + else + UA_snprintf(nsu, 100, "nsu=%.*s;", (int)id->namespaceUri.length, id->namespaceUri.data); + size_t nsulen = strlen(nsu); + + /* Combine everything */ + res = UA_ByteString_allocBuffer((UA_String*)output, outNid.length + svrlen + nsulen); + if(res == UA_STATUSCODE_GOOD) { + memcpy(output->data, svr, svrlen); + memcpy(&output->data[svrlen], nsu, nsulen); + memcpy(&output->data[svrlen+nsulen], outNid.data, outNid.length); + } + + UA_String_clear(&outNid); + return res; +} + +#ifdef UA_ENABLE_TYPEDESCRIPTION + +/***********************/ +/* Jumptable Signature */ +/***********************/ + +typedef struct UA_PrintElement { + TAILQ_ENTRY(UA_PrintElement) next; + size_t length; + UA_Byte data[]; +} UA_PrintOutput; + +typedef struct { + size_t depth; + TAILQ_HEAD(, UA_PrintElement) outputs; +} UA_PrintContext; + +typedef UA_StatusCode +(*UA_printSignature)(UA_PrintContext *ctx, const void *p, + const UA_DataType *type); + +extern const UA_printSignature printJumpTable[UA_DATATYPEKINDS]; + +/********************/ +/* Helper Functions */ +/********************/ + +static UA_PrintOutput * +UA_PrintContext_addOutput(UA_PrintContext *ctx, size_t length) { + /* Protect against overlong output in pretty-printing */ + if(length > 2<<16) + return NULL; + UA_PrintOutput *output = (UA_PrintOutput*)UA_malloc(sizeof(UA_PrintOutput) + length + 1); + if(!output) + return NULL; + output->length = length; + TAILQ_INSERT_TAIL(&ctx->outputs, output, next); + return output; +} + +static UA_StatusCode +UA_PrintContext_addNewlineTabs(UA_PrintContext *ctx, size_t tabs) { + UA_PrintOutput *out = UA_PrintContext_addOutput(ctx, tabs+1); + if(!out) + return UA_STATUSCODE_BADOUTOFMEMORY; + out->data[0] = '\n'; + for(size_t i = 1; i <= tabs; i++) + out->data[i] = '\t'; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_PrintContext_addName(UA_PrintContext *ctx, const char *name) { + size_t nameLen = strlen(name); + UA_PrintOutput *out = UA_PrintContext_addOutput(ctx, nameLen+2); + if(!out) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(&out->data, name, nameLen); + out->data[nameLen] = ':'; + out->data[nameLen+1] = ' '; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_PrintContext_addString(UA_PrintContext *ctx, const char *str) { + size_t len = strlen(str); + UA_PrintOutput *out = UA_PrintContext_addOutput(ctx, len); + if(!out) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(&out->data, str, len); + return UA_STATUSCODE_GOOD; +} + +/*********************/ +/* Printing Routines */ +/*********************/ + +static UA_StatusCode +printArray(UA_PrintContext *ctx, const void *p, const size_t length, + const UA_DataType *type); + +static UA_StatusCode +printBoolean(UA_PrintContext *ctx, const UA_Boolean *p, const UA_DataType *_) { + if(*p) + return UA_PrintContext_addString(ctx, "true"); + return UA_PrintContext_addString(ctx, "false"); +} + +static UA_StatusCode +printSByte(UA_PrintContext *ctx, const UA_SByte *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIi8, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printByte(UA_PrintContext *ctx, const UA_Byte *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIu8, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printInt16(UA_PrintContext *ctx, const UA_Int16 *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIi16, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printUInt16(UA_PrintContext *ctx, const UA_UInt16 *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIu16, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printInt32(UA_PrintContext *ctx, const UA_Int32 *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIi32, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printUInt32(UA_PrintContext *ctx, const UA_UInt32 *p, const UA_DataType *_) { + char out[32]; + UA_snprintf(out, 32, "%"PRIu32, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printInt64(UA_PrintContext *ctx, const UA_Int64 *p, const UA_DataType *_) { + char out[64]; + UA_snprintf(out, 64, "%"PRIi64, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printUInt64(UA_PrintContext *ctx, const UA_UInt64 *p, const UA_DataType *_) { + char out[64]; + UA_snprintf(out, 64, "%"PRIu64, *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printFloat(UA_PrintContext *ctx, const UA_Float *p, const UA_DataType *_) { + char out[64]; + UA_snprintf(out, 32, "%f", *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printDouble(UA_PrintContext *ctx, const UA_Double *p, const UA_DataType *_) { + char out[64]; + UA_snprintf(out, 64, "%lf", *p); + return UA_PrintContext_addString(ctx, out); +} + +static UA_StatusCode +printStatusCode(UA_PrintContext *ctx, const UA_StatusCode *p, const UA_DataType *_) { + return UA_PrintContext_addString(ctx, UA_StatusCode_name(*p)); +} + +static UA_StatusCode +printNodeId(UA_PrintContext *ctx, const UA_NodeId *p, const UA_DataType *_) { + UA_String out; + UA_String_init(&out); + UA_StatusCode res = UA_NodeId_print(p, &out); + if(res != UA_STATUSCODE_GOOD) + return res; + UA_PrintOutput *po = UA_PrintContext_addOutput(ctx, out.length); + if(po) + memcpy(po->data, out.data, out.length); + else + res = UA_STATUSCODE_BADOUTOFMEMORY; + UA_String_clear(&out); + return res; +} + +static UA_StatusCode +printExpandedNodeId(UA_PrintContext *ctx, const UA_ExpandedNodeId *p, const UA_DataType *_) { + UA_String out; + UA_String_init(&out); + UA_StatusCode res = UA_ExpandedNodeId_print(p, &out); + if(res != UA_STATUSCODE_GOOD) + return res; + UA_PrintOutput *po = UA_PrintContext_addOutput(ctx, out.length); + if(!po) + return UA_STATUSCODE_BADOUTOFMEMORY; + memcpy(po->data, out.data, out.length); + UA_String_clear(&out); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +printDateTime(UA_PrintContext *ctx, const UA_DateTime *p, const UA_DataType *_) { + UA_Int64 tOffset = UA_DateTime_localTimeUtcOffset(); + UA_DateTimeStruct dts = UA_DateTime_toStruct(*p); + char dateString[100]; + UA_snprintf((char*)dateString, 100, + "%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)", + dts.year, dts.month, dts.day, dts.hour, dts.min, + dts.sec, dts.milliSec, + (int)(tOffset / UA_DATETIME_SEC / 36)); + return UA_PrintContext_addString(ctx, dateString); +} + +static UA_StatusCode +printGuid(UA_PrintContext *ctx, const UA_Guid *p, const UA_DataType *_) { + char tmp[100]; + UA_snprintf(tmp, 100, UA_PRINTF_GUID_FORMAT, UA_PRINTF_GUID_DATA(*p)); + return UA_PrintContext_addString(ctx, tmp); +} + +static UA_StatusCode +printString(UA_PrintContext *ctx, const UA_String *p, const UA_DataType *_) { + if(!p->data) + return UA_PrintContext_addString(ctx, "NullString"); + UA_PrintOutput *out = UA_PrintContext_addOutput(ctx, p->length+2); + if(!out) + return UA_STATUSCODE_BADOUTOFMEMORY; + UA_snprintf((char*)out->data, p->length+3, "\"%.*s\"", (int)p->length, p->data); + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +printByteString(UA_PrintContext *ctx, const UA_ByteString *p, const UA_DataType *_) { + if(!p->data) + return UA_PrintContext_addString(ctx, "NullByteString"); + UA_String str = UA_BYTESTRING_NULL; + UA_StatusCode res = UA_ByteString_toBase64(p, &str); + if(res != UA_STATUSCODE_GOOD) + return res; + res = printString(ctx, &str, NULL); + UA_String_clear(&str); + return res; +} + +static UA_StatusCode +printQualifiedName(UA_PrintContext *ctx, const UA_QualifiedName *p, const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "NamespaceIndex"); + retval |= printUInt16(ctx, &p->namespaceIndex, NULL); + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Name"); + retval |= printString(ctx, &p->name, NULL); + ctx->depth--; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printLocalizedText(UA_PrintContext *ctx, const UA_LocalizedText *p, const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Locale"); + retval |= printString(ctx, &p->locale, NULL); + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Text"); + retval |= printString(ctx, &p->text, NULL); + ctx->depth--; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printVariant(UA_PrintContext *ctx, const UA_Variant *p, const UA_DataType *_) { + if(!p->type) + return UA_PrintContext_addString(ctx, "NullVariant"); + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "DataType"); + retval |= UA_PrintContext_addString(ctx, p->type->typeName); + retval |= UA_PrintContext_addString(ctx, ","); + + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Value"); + if(UA_Variant_isScalar(p)) + retval |= printJumpTable[p->type->typeKind](ctx, p->data, p->type); + else + retval |= printArray(ctx, p->data, p->arrayLength, p->type); + + if(p->arrayDimensionsSize > 0) { + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "ArrayDimensions"); + retval |= printArray(ctx, p->arrayDimensions, p->arrayDimensionsSize, + &UA_TYPES[UA_TYPES_UINT32]); + } + + ctx->depth--; + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printExtensionObject(UA_PrintContext *ctx, const UA_ExtensionObject*p, + const UA_DataType *_) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + switch(p->encoding) { + case UA_EXTENSIONOBJECT_ENCODED_NOBODY: + return UA_PrintContext_addString(ctx, "ExtensionObject(No Body)"); + case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING: + res |= UA_PrintContext_addString(ctx, "ExtensionObject(Binary Encoded) {"); + ctx->depth++; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "DataType"); + res |= printNodeId(ctx, &p->content.encoded.typeId, NULL); + res |= UA_PrintContext_addString(ctx, ","); + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "Body"); + res |= printByteString(ctx, &p->content.encoded.body, NULL); + ctx->depth--; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "}"); + break; + case UA_EXTENSIONOBJECT_ENCODED_XML: + res |= UA_PrintContext_addString(ctx, "ExtensionObject(XML Encoded) {"); + ctx->depth++; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "DataType"); + res |= printNodeId(ctx, &p->content.encoded.typeId, NULL); + res |= UA_PrintContext_addString(ctx, ","); + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "Body"); + res |= printString(ctx, (const UA_String*)&p->content.encoded.body, NULL); + ctx->depth--; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "}"); + break; + case UA_EXTENSIONOBJECT_DECODED: + case UA_EXTENSIONOBJECT_DECODED_NODELETE: + res |= UA_PrintContext_addString(ctx, "ExtensionObject {"); + ctx->depth++; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "DataType"); + res |= UA_PrintContext_addString(ctx, p->content.decoded.type->typeName); + res |= UA_PrintContext_addString(ctx, ","); + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "Body"); + res |= printJumpTable[p->content.decoded.type->typeKind](ctx, + p->content.decoded.data, + p->content.decoded.type); + ctx->depth--; + res |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + res |= UA_PrintContext_addName(ctx, "}"); + break; + default: + res = UA_STATUSCODE_BADINTERNALERROR; + break; + } + return res; +} + +static UA_StatusCode +printDataValue(UA_PrintContext *ctx, const UA_DataValue *p, const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + UA_Boolean comma = false; + + if(p->hasValue) { + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Value"); + retval |= printVariant(ctx, &p->value, NULL); + comma = true; + } + + if(p->hasStatus) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Status"); + retval |= printStatusCode(ctx, &p->status, NULL); + comma = true; + } + + if(p->hasSourceTimestamp) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "SourceTimestamp"); + retval |= printDateTime(ctx, &p->sourceTimestamp, NULL); + comma = true; + } + + if(p->hasSourcePicoseconds) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "SourcePicoseconds"); + retval |= printUInt16(ctx, &p->sourcePicoseconds, NULL); + comma = true; + } + + if(p->hasServerTimestamp) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "ServerTimestamp"); + retval |= printDateTime(ctx, &p->serverTimestamp, NULL); + comma = true; + } + + if(p->hasServerPicoseconds) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "ServerPicoseconds"); + retval |= printUInt16(ctx, &p->serverPicoseconds, NULL); + comma = true; + } + + ctx->depth--; + if(comma) { + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + } else { + retval |= UA_PrintContext_addString(ctx, " }"); + } + return retval; +} + +static UA_StatusCode +printDiagnosticInfo(UA_PrintContext *ctx, const UA_DiagnosticInfo *p, const UA_DataType *_) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + UA_Boolean comma = false; + + if(p->hasSymbolicId) { + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "SymbolicId"); + retval |= printInt32(ctx, &p->symbolicId, NULL); + comma = true; + } + + if(p->hasNamespaceUri) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "NamespaceUri"); + retval |= printInt32(ctx, &p->namespaceUri, NULL); + comma = true; + } + + if(p->hasLocalizedText) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "LocalizedText"); + retval |= printInt32(ctx, &p->localizedText, NULL); + comma = true; + } + + if(p->hasLocale) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "Locale"); + retval |= printInt32(ctx, &p->locale, NULL); + comma = true; + } + + if(p->hasAdditionalInfo) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "AdditionalInfo"); + retval |= printString(ctx, &p->additionalInfo, NULL); + comma = true; + } + + if(p->hasInnerStatusCode) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "InnerStatusCode"); + retval |= printStatusCode(ctx, &p->innerStatusCode, NULL); + comma = true; + } + + if(p->hasInnerDiagnosticInfo) { + if(comma) + retval |= UA_PrintContext_addString(ctx, ","); + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addName(ctx, "InnerDiagnosticInfo"); + retval |= printDiagnosticInfo(ctx, p->innerDiagnosticInfo, NULL); + comma = true; + } + + ctx->depth--; + if(comma) { + retval |= UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + } else { + retval |= UA_PrintContext_addString(ctx, " }"); + } + return retval; +} + +static UA_StatusCode +printArray(UA_PrintContext *ctx, const void *p, const size_t length, + const UA_DataType *type) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + if(!p) { + retval |= UA_PrintContext_addString(ctx, "Array(-1, "); + retval |= UA_PrintContext_addString(ctx, type->typeName); + retval |= UA_PrintContext_addString(ctx, ")"); + return retval; + } + + UA_UInt32 length32 = (UA_UInt32)length; + retval |= UA_PrintContext_addString(ctx, "Array("); + retval |= printUInt32(ctx, &length32, NULL); + retval |= UA_PrintContext_addString(ctx, ", "); + retval |= UA_PrintContext_addString(ctx, type->typeName); + retval |= UA_PrintContext_addString(ctx, ") {"); + ctx->depth++; + uintptr_t target = (uintptr_t)p; + for(UA_UInt32 i = 0; i < length; i++) { + UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + printUInt32(ctx, &i, NULL); + retval |= UA_PrintContext_addString(ctx, ": "); + printJumpTable[type->typeKind](ctx, (const void*)target, type); + if(i < length - 1) + retval |= UA_PrintContext_addString(ctx, ","); + target += type->memSize; + } + ctx->depth--; + UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printStructure(UA_PrintContext *ctx, const void *p, const UA_DataType *type) { + UA_StatusCode retval = UA_STATUSCODE_GOOD; + uintptr_t ptrs = (uintptr_t)p; + retval |= UA_PrintContext_addString(ctx, "{"); + ctx->depth++; + for(size_t i = 0; i < type->membersSize; ++i) { + UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + const UA_DataTypeMember *m = &type->members[i]; + const UA_DataType *mt = m->memberType; + ptrs += m->padding; + retval |= UA_PrintContext_addName(ctx, m->memberName); + if(!m->isArray) { + retval |= printJumpTable[mt->typeKind](ctx, (const void *)ptrs, mt); + ptrs += mt->memSize; + } else { + const size_t size = *((const size_t*)ptrs); + ptrs += sizeof(size_t); + retval |= printArray(ctx, *(void* const*)ptrs, size, mt); + ptrs += sizeof(void*); + } + if(i < (size_t)(type->membersSize - 1)) + retval |= UA_PrintContext_addString(ctx, ","); + } + ctx->depth--; + UA_PrintContext_addNewlineTabs(ctx, ctx->depth); + retval |= UA_PrintContext_addString(ctx, "}"); + return retval; +} + +static UA_StatusCode +printNotImplemented(UA_PrintContext *ctx, const void *p, const UA_DataType *type) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + res |= UA_PrintContext_addString(ctx, type->typeName); + res |= UA_PrintContext_addString(ctx, " (Printing Not Implemented)"); + return res; +} + +const UA_printSignature printJumpTable[UA_DATATYPEKINDS] = { + (UA_printSignature)printBoolean, + (UA_printSignature)printSByte, + (UA_printSignature)printByte, + (UA_printSignature)printInt16, + (UA_printSignature)printUInt16, + (UA_printSignature)printInt32, + (UA_printSignature)printUInt32, + (UA_printSignature)printInt64, + (UA_printSignature)printUInt64, + (UA_printSignature)printFloat, + (UA_printSignature)printDouble, + (UA_printSignature)printString, + (UA_printSignature)printDateTime, + (UA_printSignature)printGuid, + (UA_printSignature)printByteString, + (UA_printSignature)printString, /* XmlElement */ + (UA_printSignature)printNodeId, + (UA_printSignature)printExpandedNodeId, + (UA_printSignature)printStatusCode, + (UA_printSignature)printQualifiedName, + (UA_printSignature)printLocalizedText, + (UA_printSignature)printExtensionObject, + (UA_printSignature)printDataValue, + (UA_printSignature)printVariant, + (UA_printSignature)printDiagnosticInfo, + (UA_printSignature)printNotImplemented, /* Decimal */ + (UA_printSignature)printUInt32, /* Enumeration */ + (UA_printSignature)printStructure, + (UA_printSignature)printNotImplemented, /* Structure with Optional Fields */ + (UA_printSignature)printNotImplemented, /* Union */ + (UA_printSignature)printNotImplemented /* BitfieldCluster*/ +}; + +UA_StatusCode +UA_print(const void *p, const UA_DataType *type, UA_String *output) { + UA_PrintContext ctx; + ctx.depth = 0; + TAILQ_INIT(&ctx.outputs); + + /* Encode */ + UA_StatusCode retval = printJumpTable[type->typeKind](&ctx, p, type); + + /* Allocate memory for the output */ + if(retval == UA_STATUSCODE_GOOD) { + size_t total = 0; + UA_PrintOutput *out; + TAILQ_FOREACH(out, &ctx.outputs, next) + total += out->length; + retval = UA_ByteString_allocBuffer((UA_String*)output, total); + } + + /* Write the output */ + if(retval == UA_STATUSCODE_GOOD) { + size_t pos = 0; + UA_PrintOutput *out; + TAILQ_FOREACH(out, &ctx.outputs, next) { + memcpy(&output->data[pos], out->data, out->length); + pos += out->length; + } + } + + /* Free the context */ + UA_PrintOutput *o, *o2; + TAILQ_FOREACH_SAFE(o, &ctx.outputs, next, o2) { + TAILQ_REMOVE(&ctx.outputs, o, next); + UA_free(o); + } + return retval; +} + +#endif /* UA_ENABLE_TYPEDESCRIPTION */ + +/**** amalgamated original file "/build_freeRTOS/src_generated/open62541/types_generated.c" ****/ + +/********************************** + * Autogenerated -- do not modify * + **********************************/ + + +/* Boolean */ +#define Boolean_members NULL + +/* SByte */ +#define SByte_members NULL + +/* Byte */ +#define Byte_members NULL + +/* Int16 */ +#define Int16_members NULL + +/* UInt16 */ +#define UInt16_members NULL + +/* Int32 */ +#define Int32_members NULL + +/* UInt32 */ +#define UInt32_members NULL + +/* Int64 */ +#define Int64_members NULL + +/* UInt64 */ +#define UInt64_members NULL + +/* Float */ +#define Float_members NULL + +/* Double */ +#define Double_members NULL + +/* String */ +#define String_members NULL + +/* DateTime */ +#define DateTime_members NULL + +/* Guid */ +#define Guid_members NULL + +/* ByteString */ +#define ByteString_members NULL + +/* XmlElement */ +#define XmlElement_members NULL + +/* NodeId */ +#define NodeId_members NULL + +/* ExpandedNodeId */ +#define ExpandedNodeId_members NULL + +/* StatusCode */ +#define StatusCode_members NULL + +/* QualifiedName */ +#define QualifiedName_members NULL + +/* LocalizedText */ +#define LocalizedText_members NULL + +/* ExtensionObject */ +#define ExtensionObject_members NULL + +/* DataValue */ +#define DataValue_members NULL + +/* Variant */ +#define Variant_members NULL + +/* DiagnosticInfo */ +#define DiagnosticInfo_members NULL + +/* KeyValuePair */ +static UA_DataTypeMember KeyValuePair_members[2] = { +{ + UA_TYPENAME("Key") /* .memberName */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ + offsetof(UA_KeyValuePair, value) - offsetof(UA_KeyValuePair, key) - sizeof(UA_QualifiedName), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* NodeClass */ +#define NodeClass_members NULL + +/* StructureType */ +#define StructureType_members NULL + +/* StructureField */ +static UA_DataTypeMember StructureField_members[7] = { +{ + UA_TYPENAME("Name") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_StructureField, description) - offsetof(UA_StructureField, name) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DataType") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_StructureField, dataType) - offsetof(UA_StructureField, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ValueRank") /* .memberName */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ + offsetof(UA_StructureField, valueRank) - offsetof(UA_StructureField, dataType) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ArrayDimensions") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_StructureField, arrayDimensionsSize) - offsetof(UA_StructureField, valueRank) - sizeof(UA_Int32), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxStringLength") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_StructureField, maxStringLength) - offsetof(UA_StructureField, arrayDimensions) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IsOptional") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_StructureField, isOptional) - offsetof(UA_StructureField, maxStringLength) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* StructureDefinition */ +static UA_DataTypeMember StructureDefinition_members[4] = { +{ + UA_TYPENAME("DefaultEncodingId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BaseDataType") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_StructureDefinition, baseDataType) - offsetof(UA_StructureDefinition, defaultEncodingId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("StructureType") /* .memberName */ + &UA_TYPES[UA_TYPES_STRUCTURETYPE], /* .memberType */ + offsetof(UA_StructureDefinition, structureType) - offsetof(UA_StructureDefinition, baseDataType) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Fields") /* .memberName */ + &UA_TYPES[UA_TYPES_STRUCTUREFIELD], /* .memberType */ + offsetof(UA_StructureDefinition, fieldsSize) - offsetof(UA_StructureDefinition, structureType) - sizeof(UA_StructureType), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* Argument */ +static UA_DataTypeMember Argument_members[5] = { +{ + UA_TYPENAME("Name") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DataType") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_Argument, dataType) - offsetof(UA_Argument, name) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ValueRank") /* .memberName */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ + offsetof(UA_Argument, valueRank) - offsetof(UA_Argument, dataType) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ArrayDimensions") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_Argument, arrayDimensionsSize) - offsetof(UA_Argument, valueRank) - sizeof(UA_Int32), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_Argument, description) - offsetof(UA_Argument, arrayDimensions) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* EnumValueType */ +static UA_DataTypeMember EnumValueType_members[3] = { +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_INT64], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_EnumValueType, displayName) - offsetof(UA_EnumValueType, value) - sizeof(UA_Int64), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_EnumValueType, description) - offsetof(UA_EnumValueType, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* EnumField */ +static UA_DataTypeMember EnumField_members[4] = { +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_INT64], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_EnumField, displayName) - offsetof(UA_EnumField, value) - sizeof(UA_Int64), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_EnumField, description) - offsetof(UA_EnumField, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Name") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_EnumField, name) - offsetof(UA_EnumField, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* Duration */ +#define Duration_members NULL + +/* UtcTime */ +#define UtcTime_members NULL + +/* LocaleId */ +#define LocaleId_members NULL + +/* TimeZoneDataType */ +static UA_DataTypeMember TimeZoneDataType_members[2] = { +{ + UA_TYPENAME("Offset") /* .memberName */ + &UA_TYPES[UA_TYPES_INT16], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DaylightSavingInOffset") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_TimeZoneDataType, daylightSavingInOffset) - offsetof(UA_TimeZoneDataType, offset) - sizeof(UA_Int16), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ApplicationType */ +#define ApplicationType_members NULL + +/* ApplicationDescription */ +static UA_DataTypeMember ApplicationDescription_members[7] = { +{ + UA_TYPENAME("ApplicationUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ProductUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_ApplicationDescription, productUri) - offsetof(UA_ApplicationDescription, applicationUri) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ApplicationName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ApplicationDescription, applicationName) - offsetof(UA_ApplicationDescription, productUri) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ApplicationType") /* .memberName */ + &UA_TYPES[UA_TYPES_APPLICATIONTYPE], /* .memberType */ + offsetof(UA_ApplicationDescription, applicationType) - offsetof(UA_ApplicationDescription, applicationName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("GatewayServerUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_ApplicationDescription, gatewayServerUri) - offsetof(UA_ApplicationDescription, applicationType) - sizeof(UA_ApplicationType), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiscoveryProfileUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_ApplicationDescription, discoveryProfileUri) - offsetof(UA_ApplicationDescription, gatewayServerUri) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiscoveryUrls") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_ApplicationDescription, discoveryUrlsSize) - offsetof(UA_ApplicationDescription, discoveryProfileUri) - sizeof(UA_String), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* RequestHeader */ +static UA_DataTypeMember RequestHeader_members[7] = { +{ + UA_TYPENAME("AuthenticationToken") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Timestamp") /* .memberName */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ + offsetof(UA_RequestHeader, timestamp) - offsetof(UA_RequestHeader, authenticationToken) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestHandle") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_RequestHeader, requestHandle) - offsetof(UA_RequestHeader, timestamp) - sizeof(UA_DateTime), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReturnDiagnostics") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_RequestHeader, returnDiagnostics) - offsetof(UA_RequestHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AuditEntryId") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_RequestHeader, auditEntryId) - offsetof(UA_RequestHeader, returnDiagnostics) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TimeoutHint") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_RequestHeader, timeoutHint) - offsetof(UA_RequestHeader, auditEntryId) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AdditionalHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ + offsetof(UA_RequestHeader, additionalHeader) - offsetof(UA_RequestHeader, timeoutHint) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ResponseHeader */ +static UA_DataTypeMember ResponseHeader_members[6] = { +{ + UA_TYPENAME("Timestamp") /* .memberName */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestHandle") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ResponseHeader, requestHandle) - offsetof(UA_ResponseHeader, timestamp) - sizeof(UA_DateTime), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServiceResult") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_ResponseHeader, serviceResult) - offsetof(UA_ResponseHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServiceDiagnostics") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_ResponseHeader, serviceDiagnostics) - offsetof(UA_ResponseHeader, serviceResult) - sizeof(UA_StatusCode), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("StringTable") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_ResponseHeader, stringTableSize) - offsetof(UA_ResponseHeader, serviceDiagnostics) - sizeof(UA_DiagnosticInfo), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AdditionalHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ + offsetof(UA_ResponseHeader, additionalHeader) - offsetof(UA_ResponseHeader, stringTable) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ServiceFault */ +static UA_DataTypeMember ServiceFault_members[1] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* FindServersRequest */ +static UA_DataTypeMember FindServersRequest_members[4] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EndpointUrl") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_FindServersRequest, endpointUrl) - offsetof(UA_FindServersRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("LocaleIds") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_FindServersRequest, localeIdsSize) - offsetof(UA_FindServersRequest, endpointUrl) - sizeof(UA_String), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerUris") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_FindServersRequest, serverUrisSize) - offsetof(UA_FindServersRequest, localeIds) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* FindServersResponse */ +static UA_DataTypeMember FindServersResponse_members[2] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Servers") /* .memberName */ + &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */ + offsetof(UA_FindServersResponse, serversSize) - offsetof(UA_FindServersResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* MessageSecurityMode */ +#define MessageSecurityMode_members NULL + +/* UserTokenType */ +#define UserTokenType_members NULL + +/* UserTokenPolicy */ +static UA_DataTypeMember UserTokenPolicy_members[5] = { +{ + UA_TYPENAME("PolicyId") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TokenType") /* .memberName */ + &UA_TYPES[UA_TYPES_USERTOKENTYPE], /* .memberType */ + offsetof(UA_UserTokenPolicy, tokenType) - offsetof(UA_UserTokenPolicy, policyId) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IssuedTokenType") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_UserTokenPolicy, issuedTokenType) - offsetof(UA_UserTokenPolicy, tokenType) - sizeof(UA_UserTokenType), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IssuerEndpointUrl") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - offsetof(UA_UserTokenPolicy, issuedTokenType) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SecurityPolicyUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_UserTokenPolicy, securityPolicyUri) - offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* EndpointDescription */ +static UA_DataTypeMember EndpointDescription_members[8] = { +{ + UA_TYPENAME("EndpointUrl") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Server") /* .memberName */ + &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */ + offsetof(UA_EndpointDescription, server) - offsetof(UA_EndpointDescription, endpointUrl) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerCertificate") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_EndpointDescription, serverCertificate) - offsetof(UA_EndpointDescription, server) - sizeof(UA_ApplicationDescription), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SecurityMode") /* .memberName */ + &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */ + offsetof(UA_EndpointDescription, securityMode) - offsetof(UA_EndpointDescription, serverCertificate) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SecurityPolicyUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_EndpointDescription, securityPolicyUri) - offsetof(UA_EndpointDescription, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserIdentityTokens") /* .memberName */ + &UA_TYPES[UA_TYPES_USERTOKENPOLICY], /* .memberType */ + offsetof(UA_EndpointDescription, userIdentityTokensSize) - offsetof(UA_EndpointDescription, securityPolicyUri) - sizeof(UA_String), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TransportProfileUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_EndpointDescription, transportProfileUri) - offsetof(UA_EndpointDescription, userIdentityTokens) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SecurityLevel") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ + offsetof(UA_EndpointDescription, securityLevel) - offsetof(UA_EndpointDescription, transportProfileUri) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* GetEndpointsRequest */ +static UA_DataTypeMember GetEndpointsRequest_members[4] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EndpointUrl") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_GetEndpointsRequest, endpointUrl) - offsetof(UA_GetEndpointsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("LocaleIds") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_GetEndpointsRequest, localeIdsSize) - offsetof(UA_GetEndpointsRequest, endpointUrl) - sizeof(UA_String), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ProfileUris") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_GetEndpointsRequest, profileUrisSize) - offsetof(UA_GetEndpointsRequest, localeIds) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* GetEndpointsResponse */ +static UA_DataTypeMember GetEndpointsResponse_members[2] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Endpoints") /* .memberName */ + &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */ + offsetof(UA_GetEndpointsResponse, endpointsSize) - offsetof(UA_GetEndpointsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* SecurityTokenRequestType */ +#define SecurityTokenRequestType_members NULL + +/* ChannelSecurityToken */ +static UA_DataTypeMember ChannelSecurityToken_members[4] = { +{ + UA_TYPENAME("ChannelId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TokenId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ChannelSecurityToken, tokenId) - offsetof(UA_ChannelSecurityToken, channelId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("CreatedAt") /* .memberName */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ + offsetof(UA_ChannelSecurityToken, createdAt) - offsetof(UA_ChannelSecurityToken, tokenId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedLifetime") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ChannelSecurityToken, revisedLifetime) - offsetof(UA_ChannelSecurityToken, createdAt) - sizeof(UA_DateTime), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* OpenSecureChannelRequest */ +static UA_DataTypeMember OpenSecureChannelRequest_members[6] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ClientProtocolVersion") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - offsetof(UA_OpenSecureChannelRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestType") /* .memberName */ + &UA_TYPES[UA_TYPES_SECURITYTOKENREQUESTTYPE], /* .memberType */ + offsetof(UA_OpenSecureChannelRequest, requestType) - offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SecurityMode") /* .memberName */ + &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */ + offsetof(UA_OpenSecureChannelRequest, securityMode) - offsetof(UA_OpenSecureChannelRequest, requestType) - sizeof(UA_SecurityTokenRequestType), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ClientNonce") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_OpenSecureChannelRequest, clientNonce) - offsetof(UA_OpenSecureChannelRequest, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedLifetime") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_OpenSecureChannelRequest, requestedLifetime) - offsetof(UA_OpenSecureChannelRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* OpenSecureChannelResponse */ +static UA_DataTypeMember OpenSecureChannelResponse_members[4] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerProtocolVersion") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - offsetof(UA_OpenSecureChannelResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SecurityToken") /* .memberName */ + &UA_TYPES[UA_TYPES_CHANNELSECURITYTOKEN], /* .memberType */ + offsetof(UA_OpenSecureChannelResponse, securityToken) - offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerNonce") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_OpenSecureChannelResponse, serverNonce) - offsetof(UA_OpenSecureChannelResponse, securityToken) - sizeof(UA_ChannelSecurityToken), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* CloseSecureChannelRequest */ +static UA_DataTypeMember CloseSecureChannelRequest_members[1] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* CloseSecureChannelResponse */ +static UA_DataTypeMember CloseSecureChannelResponse_members[1] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* SignedSoftwareCertificate */ +static UA_DataTypeMember SignedSoftwareCertificate_members[2] = { +{ + UA_TYPENAME("CertificateData") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Signature") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_SignedSoftwareCertificate, signature) - offsetof(UA_SignedSoftwareCertificate, certificateData) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* SignatureData */ +static UA_DataTypeMember SignatureData_members[2] = { +{ + UA_TYPENAME("Algorithm") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Signature") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_SignatureData, signature) - offsetof(UA_SignatureData, algorithm) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* CreateSessionRequest */ +static UA_DataTypeMember CreateSessionRequest_members[9] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ClientDescription") /* .memberName */ + &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */ + offsetof(UA_CreateSessionRequest, clientDescription) - offsetof(UA_CreateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_CreateSessionRequest, serverUri) - offsetof(UA_CreateSessionRequest, clientDescription) - sizeof(UA_ApplicationDescription), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EndpointUrl") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_CreateSessionRequest, endpointUrl) - offsetof(UA_CreateSessionRequest, serverUri) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SessionName") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_CreateSessionRequest, sessionName) - offsetof(UA_CreateSessionRequest, endpointUrl) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ClientNonce") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_CreateSessionRequest, clientNonce) - offsetof(UA_CreateSessionRequest, sessionName) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ClientCertificate") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_CreateSessionRequest, clientCertificate) - offsetof(UA_CreateSessionRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedSessionTimeout") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - offsetof(UA_CreateSessionRequest, clientCertificate) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxResponseMessageSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_CreateSessionRequest, maxResponseMessageSize) - offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* CreateSessionResponse */ +static UA_DataTypeMember CreateSessionResponse_members[10] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SessionId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_CreateSessionResponse, sessionId) - offsetof(UA_CreateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AuthenticationToken") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_CreateSessionResponse, authenticationToken) - offsetof(UA_CreateSessionResponse, sessionId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedSessionTimeout") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - offsetof(UA_CreateSessionResponse, authenticationToken) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerNonce") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_CreateSessionResponse, serverNonce) - offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerCertificate") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_CreateSessionResponse, serverCertificate) - offsetof(UA_CreateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerEndpoints") /* .memberName */ + &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */ + offsetof(UA_CreateSessionResponse, serverEndpointsSize) - offsetof(UA_CreateSessionResponse, serverCertificate) - sizeof(UA_ByteString), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerSoftwareCertificates") /* .memberName */ + &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], /* .memberType */ + offsetof(UA_CreateSessionResponse, serverSoftwareCertificatesSize) - offsetof(UA_CreateSessionResponse, serverEndpoints) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerSignature") /* .memberName */ + &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */ + offsetof(UA_CreateSessionResponse, serverSignature) - offsetof(UA_CreateSessionResponse, serverSoftwareCertificates) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxRequestMessageSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_CreateSessionResponse, maxRequestMessageSize) - offsetof(UA_CreateSessionResponse, serverSignature) - sizeof(UA_SignatureData), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* UserIdentityToken */ +static UA_DataTypeMember UserIdentityToken_members[1] = { +{ + UA_TYPENAME("PolicyId") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AnonymousIdentityToken */ +static UA_DataTypeMember AnonymousIdentityToken_members[1] = { +{ + UA_TYPENAME("PolicyId") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* UserNameIdentityToken */ +static UA_DataTypeMember UserNameIdentityToken_members[4] = { +{ + UA_TYPENAME("PolicyId") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserName") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_UserNameIdentityToken, userName) - offsetof(UA_UserNameIdentityToken, policyId) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Password") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_UserNameIdentityToken, password) - offsetof(UA_UserNameIdentityToken, userName) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EncryptionAlgorithm") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_UserNameIdentityToken, encryptionAlgorithm) - offsetof(UA_UserNameIdentityToken, password) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* X509IdentityToken */ +static UA_DataTypeMember X509IdentityToken_members[2] = { +{ + UA_TYPENAME("PolicyId") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("CertificateData") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_X509IdentityToken, certificateData) - offsetof(UA_X509IdentityToken, policyId) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* IssuedIdentityToken */ +static UA_DataTypeMember IssuedIdentityToken_members[3] = { +{ + UA_TYPENAME("PolicyId") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TokenData") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_IssuedIdentityToken, tokenData) - offsetof(UA_IssuedIdentityToken, policyId) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EncryptionAlgorithm") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_IssuedIdentityToken, encryptionAlgorithm) - offsetof(UA_IssuedIdentityToken, tokenData) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ActivateSessionRequest */ +static UA_DataTypeMember ActivateSessionRequest_members[6] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ClientSignature") /* .memberName */ + &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */ + offsetof(UA_ActivateSessionRequest, clientSignature) - offsetof(UA_ActivateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ClientSoftwareCertificates") /* .memberName */ + &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], /* .memberType */ + offsetof(UA_ActivateSessionRequest, clientSoftwareCertificatesSize) - offsetof(UA_ActivateSessionRequest, clientSignature) - sizeof(UA_SignatureData), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("LocaleIds") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_ActivateSessionRequest, localeIdsSize) - offsetof(UA_ActivateSessionRequest, clientSoftwareCertificates) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserIdentityToken") /* .memberName */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ + offsetof(UA_ActivateSessionRequest, userIdentityToken) - offsetof(UA_ActivateSessionRequest, localeIds) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserTokenSignature") /* .memberName */ + &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */ + offsetof(UA_ActivateSessionRequest, userTokenSignature) - offsetof(UA_ActivateSessionRequest, userIdentityToken) - sizeof(UA_ExtensionObject), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ActivateSessionResponse */ +static UA_DataTypeMember ActivateSessionResponse_members[4] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ServerNonce") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_ActivateSessionResponse, serverNonce) - offsetof(UA_ActivateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_ActivateSessionResponse, resultsSize) - offsetof(UA_ActivateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_ActivateSessionResponse, diagnosticInfosSize) - offsetof(UA_ActivateSessionResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* CloseSessionRequest */ +static UA_DataTypeMember CloseSessionRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DeleteSubscriptions") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_CloseSessionRequest, deleteSubscriptions) - offsetof(UA_CloseSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* CloseSessionResponse */ +static UA_DataTypeMember CloseSessionResponse_members[1] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* NodeAttributesMask */ +#define NodeAttributesMask_members NULL + +/* NodeAttributes */ +static UA_DataTypeMember NodeAttributes_members[5] = { +{ + UA_TYPENAME("SpecifiedAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_NodeAttributes, displayName) - offsetof(UA_NodeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_NodeAttributes, description) - offsetof(UA_NodeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_NodeAttributes, writeMask) - offsetof(UA_NodeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserWriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_NodeAttributes, userWriteMask) - offsetof(UA_NodeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ObjectAttributes */ +static UA_DataTypeMember ObjectAttributes_members[6] = { +{ + UA_TYPENAME("SpecifiedAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ObjectAttributes, displayName) - offsetof(UA_ObjectAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ObjectAttributes, description) - offsetof(UA_ObjectAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ObjectAttributes, writeMask) - offsetof(UA_ObjectAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserWriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ObjectAttributes, userWriteMask) - offsetof(UA_ObjectAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EventNotifier") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ + offsetof(UA_ObjectAttributes, eventNotifier) - offsetof(UA_ObjectAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* VariableAttributes */ +static UA_DataTypeMember VariableAttributes_members[13] = { +{ + UA_TYPENAME("SpecifiedAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_VariableAttributes, displayName) - offsetof(UA_VariableAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_VariableAttributes, description) - offsetof(UA_VariableAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_VariableAttributes, writeMask) - offsetof(UA_VariableAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserWriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_VariableAttributes, userWriteMask) - offsetof(UA_VariableAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ + offsetof(UA_VariableAttributes, value) - offsetof(UA_VariableAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DataType") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_VariableAttributes, dataType) - offsetof(UA_VariableAttributes, value) - sizeof(UA_Variant), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ValueRank") /* .memberName */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ + offsetof(UA_VariableAttributes, valueRank) - offsetof(UA_VariableAttributes, dataType) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ArrayDimensions") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_VariableAttributes, arrayDimensionsSize) - offsetof(UA_VariableAttributes, valueRank) - sizeof(UA_Int32), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AccessLevel") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ + offsetof(UA_VariableAttributes, accessLevel) - offsetof(UA_VariableAttributes, arrayDimensions) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserAccessLevel") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ + offsetof(UA_VariableAttributes, userAccessLevel) - offsetof(UA_VariableAttributes, accessLevel) - sizeof(UA_Byte), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MinimumSamplingInterval") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_VariableAttributes, minimumSamplingInterval) - offsetof(UA_VariableAttributes, userAccessLevel) - sizeof(UA_Byte), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Historizing") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_VariableAttributes, historizing) - offsetof(UA_VariableAttributes, minimumSamplingInterval) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* MethodAttributes */ +static UA_DataTypeMember MethodAttributes_members[7] = { +{ + UA_TYPENAME("SpecifiedAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_MethodAttributes, displayName) - offsetof(UA_MethodAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_MethodAttributes, description) - offsetof(UA_MethodAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_MethodAttributes, writeMask) - offsetof(UA_MethodAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserWriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_MethodAttributes, userWriteMask) - offsetof(UA_MethodAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Executable") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_MethodAttributes, executable) - offsetof(UA_MethodAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserExecutable") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_MethodAttributes, userExecutable) - offsetof(UA_MethodAttributes, executable) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ObjectTypeAttributes */ +static UA_DataTypeMember ObjectTypeAttributes_members[6] = { +{ + UA_TYPENAME("SpecifiedAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ObjectTypeAttributes, displayName) - offsetof(UA_ObjectTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ObjectTypeAttributes, description) - offsetof(UA_ObjectTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ObjectTypeAttributes, writeMask) - offsetof(UA_ObjectTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserWriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ObjectTypeAttributes, userWriteMask) - offsetof(UA_ObjectTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IsAbstract") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_ObjectTypeAttributes, isAbstract) - offsetof(UA_ObjectTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* VariableTypeAttributes */ +static UA_DataTypeMember VariableTypeAttributes_members[10] = { +{ + UA_TYPENAME("SpecifiedAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_VariableTypeAttributes, displayName) - offsetof(UA_VariableTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_VariableTypeAttributes, description) - offsetof(UA_VariableTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_VariableTypeAttributes, writeMask) - offsetof(UA_VariableTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserWriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_VariableTypeAttributes, userWriteMask) - offsetof(UA_VariableTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ + offsetof(UA_VariableTypeAttributes, value) - offsetof(UA_VariableTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DataType") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_VariableTypeAttributes, dataType) - offsetof(UA_VariableTypeAttributes, value) - sizeof(UA_Variant), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ValueRank") /* .memberName */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ + offsetof(UA_VariableTypeAttributes, valueRank) - offsetof(UA_VariableTypeAttributes, dataType) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ArrayDimensions") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_VariableTypeAttributes, arrayDimensionsSize) - offsetof(UA_VariableTypeAttributes, valueRank) - sizeof(UA_Int32), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IsAbstract") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_VariableTypeAttributes, isAbstract) - offsetof(UA_VariableTypeAttributes, arrayDimensions) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ReferenceTypeAttributes */ +static UA_DataTypeMember ReferenceTypeAttributes_members[8] = { +{ + UA_TYPENAME("SpecifiedAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ReferenceTypeAttributes, displayName) - offsetof(UA_ReferenceTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ReferenceTypeAttributes, description) - offsetof(UA_ReferenceTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ReferenceTypeAttributes, writeMask) - offsetof(UA_ReferenceTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserWriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ReferenceTypeAttributes, userWriteMask) - offsetof(UA_ReferenceTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IsAbstract") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_ReferenceTypeAttributes, isAbstract) - offsetof(UA_ReferenceTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Symmetric") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_ReferenceTypeAttributes, symmetric) - offsetof(UA_ReferenceTypeAttributes, isAbstract) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("InverseName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ReferenceTypeAttributes, inverseName) - offsetof(UA_ReferenceTypeAttributes, symmetric) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* DataTypeAttributes */ +static UA_DataTypeMember DataTypeAttributes_members[6] = { +{ + UA_TYPENAME("SpecifiedAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_DataTypeAttributes, displayName) - offsetof(UA_DataTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_DataTypeAttributes, description) - offsetof(UA_DataTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_DataTypeAttributes, writeMask) - offsetof(UA_DataTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserWriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_DataTypeAttributes, userWriteMask) - offsetof(UA_DataTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IsAbstract") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_DataTypeAttributes, isAbstract) - offsetof(UA_DataTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ViewAttributes */ +static UA_DataTypeMember ViewAttributes_members[7] = { +{ + UA_TYPENAME("SpecifiedAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ViewAttributes, displayName) - offsetof(UA_ViewAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ViewAttributes, description) - offsetof(UA_ViewAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ViewAttributes, writeMask) - offsetof(UA_ViewAttributes, description) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UserWriteMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ViewAttributes, userWriteMask) - offsetof(UA_ViewAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ContainsNoLoops") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_ViewAttributes, containsNoLoops) - offsetof(UA_ViewAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EventNotifier") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ + offsetof(UA_ViewAttributes, eventNotifier) - offsetof(UA_ViewAttributes, containsNoLoops) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AddNodesItem */ +static UA_DataTypeMember AddNodesItem_members[7] = { +{ + UA_TYPENAME("ParentNodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReferenceTypeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_AddNodesItem, referenceTypeId) - offsetof(UA_AddNodesItem, parentNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedNewNodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ + offsetof(UA_AddNodesItem, requestedNewNodeId) - offsetof(UA_AddNodesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BrowseName") /* .memberName */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ + offsetof(UA_AddNodesItem, browseName) - offsetof(UA_AddNodesItem, requestedNewNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodeClass") /* .memberName */ + &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */ + offsetof(UA_AddNodesItem, nodeClass) - offsetof(UA_AddNodesItem, browseName) - sizeof(UA_QualifiedName), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodeAttributes") /* .memberName */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ + offsetof(UA_AddNodesItem, nodeAttributes) - offsetof(UA_AddNodesItem, nodeClass) - sizeof(UA_NodeClass), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TypeDefinition") /* .memberName */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ + offsetof(UA_AddNodesItem, typeDefinition) - offsetof(UA_AddNodesItem, nodeAttributes) - sizeof(UA_ExtensionObject), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AddNodesResult */ +static UA_DataTypeMember AddNodesResult_members[2] = { +{ + UA_TYPENAME("StatusCode") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AddedNodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_AddNodesResult, addedNodeId) - offsetof(UA_AddNodesResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AddNodesRequest */ +static UA_DataTypeMember AddNodesRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodesToAdd") /* .memberName */ + &UA_TYPES[UA_TYPES_ADDNODESITEM], /* .memberType */ + offsetof(UA_AddNodesRequest, nodesToAddSize) - offsetof(UA_AddNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* AddNodesResponse */ +static UA_DataTypeMember AddNodesResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_ADDNODESRESULT], /* .memberType */ + offsetof(UA_AddNodesResponse, resultsSize) - offsetof(UA_AddNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_AddNodesResponse, diagnosticInfosSize) - offsetof(UA_AddNodesResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* AddReferencesItem */ +static UA_DataTypeMember AddReferencesItem_members[6] = { +{ + UA_TYPENAME("SourceNodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReferenceTypeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_AddReferencesItem, referenceTypeId) - offsetof(UA_AddReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IsForward") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_AddReferencesItem, isForward) - offsetof(UA_AddReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TargetServerUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_AddReferencesItem, targetServerUri) - offsetof(UA_AddReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TargetNodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ + offsetof(UA_AddReferencesItem, targetNodeId) - offsetof(UA_AddReferencesItem, targetServerUri) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TargetNodeClass") /* .memberName */ + &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */ + offsetof(UA_AddReferencesItem, targetNodeClass) - offsetof(UA_AddReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AddReferencesRequest */ +static UA_DataTypeMember AddReferencesRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReferencesToAdd") /* .memberName */ + &UA_TYPES[UA_TYPES_ADDREFERENCESITEM], /* .memberType */ + offsetof(UA_AddReferencesRequest, referencesToAddSize) - offsetof(UA_AddReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* AddReferencesResponse */ +static UA_DataTypeMember AddReferencesResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_AddReferencesResponse, resultsSize) - offsetof(UA_AddReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_AddReferencesResponse, diagnosticInfosSize) - offsetof(UA_AddReferencesResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteNodesItem */ +static UA_DataTypeMember DeleteNodesItem_members[2] = { +{ + UA_TYPENAME("NodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DeleteTargetReferences") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_DeleteNodesItem, deleteTargetReferences) - offsetof(UA_DeleteNodesItem, nodeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteNodesRequest */ +static UA_DataTypeMember DeleteNodesRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodesToDelete") /* .memberName */ + &UA_TYPES[UA_TYPES_DELETENODESITEM], /* .memberType */ + offsetof(UA_DeleteNodesRequest, nodesToDeleteSize) - offsetof(UA_DeleteNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteNodesResponse */ +static UA_DataTypeMember DeleteNodesResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_DeleteNodesResponse, resultsSize) - offsetof(UA_DeleteNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_DeleteNodesResponse, diagnosticInfosSize) - offsetof(UA_DeleteNodesResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteReferencesItem */ +static UA_DataTypeMember DeleteReferencesItem_members[5] = { +{ + UA_TYPENAME("SourceNodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReferenceTypeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_DeleteReferencesItem, referenceTypeId) - offsetof(UA_DeleteReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IsForward") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_DeleteReferencesItem, isForward) - offsetof(UA_DeleteReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TargetNodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ + offsetof(UA_DeleteReferencesItem, targetNodeId) - offsetof(UA_DeleteReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DeleteBidirectional") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_DeleteReferencesItem, deleteBidirectional) - offsetof(UA_DeleteReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteReferencesRequest */ +static UA_DataTypeMember DeleteReferencesRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReferencesToDelete") /* .memberName */ + &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM], /* .memberType */ + offsetof(UA_DeleteReferencesRequest, referencesToDeleteSize) - offsetof(UA_DeleteReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteReferencesResponse */ +static UA_DataTypeMember DeleteReferencesResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_DeleteReferencesResponse, resultsSize) - offsetof(UA_DeleteReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_DeleteReferencesResponse, diagnosticInfosSize) - offsetof(UA_DeleteReferencesResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowseDirection */ +#define BrowseDirection_members NULL + +/* ViewDescription */ +static UA_DataTypeMember ViewDescription_members[3] = { +{ + UA_TYPENAME("ViewId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Timestamp") /* .memberName */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ + offsetof(UA_ViewDescription, timestamp) - offsetof(UA_ViewDescription, viewId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ViewVersion") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ViewDescription, viewVersion) - offsetof(UA_ViewDescription, timestamp) - sizeof(UA_DateTime), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowseDescription */ +static UA_DataTypeMember BrowseDescription_members[6] = { +{ + UA_TYPENAME("NodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BrowseDirection") /* .memberName */ + &UA_TYPES[UA_TYPES_BROWSEDIRECTION], /* .memberType */ + offsetof(UA_BrowseDescription, browseDirection) - offsetof(UA_BrowseDescription, nodeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReferenceTypeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_BrowseDescription, referenceTypeId) - offsetof(UA_BrowseDescription, browseDirection) - sizeof(UA_BrowseDirection), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IncludeSubtypes") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_BrowseDescription, includeSubtypes) - offsetof(UA_BrowseDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodeClassMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_BrowseDescription, nodeClassMask) - offsetof(UA_BrowseDescription, includeSubtypes) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ResultMask") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_BrowseDescription, resultMask) - offsetof(UA_BrowseDescription, nodeClassMask) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowseResultMask */ +#define BrowseResultMask_members NULL + +/* ReferenceDescription */ +static UA_DataTypeMember ReferenceDescription_members[7] = { +{ + UA_TYPENAME("ReferenceTypeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IsForward") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_ReferenceDescription, isForward) - offsetof(UA_ReferenceDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ + offsetof(UA_ReferenceDescription, nodeId) - offsetof(UA_ReferenceDescription, isForward) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BrowseName") /* .memberName */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ + offsetof(UA_ReferenceDescription, browseName) - offsetof(UA_ReferenceDescription, nodeId) - sizeof(UA_ExpandedNodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ReferenceDescription, displayName) - offsetof(UA_ReferenceDescription, browseName) - sizeof(UA_QualifiedName), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodeClass") /* .memberName */ + &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */ + offsetof(UA_ReferenceDescription, nodeClass) - offsetof(UA_ReferenceDescription, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TypeDefinition") /* .memberName */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ + offsetof(UA_ReferenceDescription, typeDefinition) - offsetof(UA_ReferenceDescription, nodeClass) - sizeof(UA_NodeClass), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowseResult */ +static UA_DataTypeMember BrowseResult_members[3] = { +{ + UA_TYPENAME("StatusCode") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ContinuationPoint") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_BrowseResult, continuationPoint) - offsetof(UA_BrowseResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("References") /* .memberName */ + &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], /* .memberType */ + offsetof(UA_BrowseResult, referencesSize) - offsetof(UA_BrowseResult, continuationPoint) - sizeof(UA_ByteString), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowseRequest */ +static UA_DataTypeMember BrowseRequest_members[4] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("View") /* .memberName */ + &UA_TYPES[UA_TYPES_VIEWDESCRIPTION], /* .memberType */ + offsetof(UA_BrowseRequest, view) - offsetof(UA_BrowseRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedMaxReferencesPerNode") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - offsetof(UA_BrowseRequest, view) - sizeof(UA_ViewDescription), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodesToBrowse") /* .memberName */ + &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION], /* .memberType */ + offsetof(UA_BrowseRequest, nodesToBrowseSize) - offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - sizeof(UA_UInt32), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowseResponse */ +static UA_DataTypeMember BrowseResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_BROWSERESULT], /* .memberType */ + offsetof(UA_BrowseResponse, resultsSize) - offsetof(UA_BrowseResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_BrowseResponse, diagnosticInfosSize) - offsetof(UA_BrowseResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowseNextRequest */ +static UA_DataTypeMember BrowseNextRequest_members[3] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReleaseContinuationPoints") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - offsetof(UA_BrowseNextRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ContinuationPoints") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_BrowseNextRequest, continuationPointsSize) - offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - sizeof(UA_Boolean), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowseNextResponse */ +static UA_DataTypeMember BrowseNextResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_BROWSERESULT], /* .memberType */ + offsetof(UA_BrowseNextResponse, resultsSize) - offsetof(UA_BrowseNextResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_BrowseNextResponse, diagnosticInfosSize) - offsetof(UA_BrowseNextResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* RelativePathElement */ +static UA_DataTypeMember RelativePathElement_members[4] = { +{ + UA_TYPENAME("ReferenceTypeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IsInverse") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_RelativePathElement, isInverse) - offsetof(UA_RelativePathElement, referenceTypeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IncludeSubtypes") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_RelativePathElement, includeSubtypes) - offsetof(UA_RelativePathElement, isInverse) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TargetName") /* .memberName */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ + offsetof(UA_RelativePathElement, targetName) - offsetof(UA_RelativePathElement, includeSubtypes) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* RelativePath */ +static UA_DataTypeMember RelativePath_members[1] = { +{ + UA_TYPENAME("Elements") /* .memberName */ + &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT], /* .memberType */ + 0, /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowsePath */ +static UA_DataTypeMember BrowsePath_members[2] = { +{ + UA_TYPENAME("StartingNode") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RelativePath") /* .memberName */ + &UA_TYPES[UA_TYPES_RELATIVEPATH], /* .memberType */ + offsetof(UA_BrowsePath, relativePath) - offsetof(UA_BrowsePath, startingNode) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowsePathTarget */ +static UA_DataTypeMember BrowsePathTarget_members[2] = { +{ + UA_TYPENAME("TargetId") /* .memberName */ + &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RemainingPathIndex") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_BrowsePathTarget, remainingPathIndex) - offsetof(UA_BrowsePathTarget, targetId) - sizeof(UA_ExpandedNodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* BrowsePathResult */ +static UA_DataTypeMember BrowsePathResult_members[2] = { +{ + UA_TYPENAME("StatusCode") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Targets") /* .memberName */ + &UA_TYPES[UA_TYPES_BROWSEPATHTARGET], /* .memberType */ + offsetof(UA_BrowsePathResult, targetsSize) - offsetof(UA_BrowsePathResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* TranslateBrowsePathsToNodeIdsRequest */ +static UA_DataTypeMember TranslateBrowsePathsToNodeIdsRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BrowsePaths") /* .memberName */ + &UA_TYPES[UA_TYPES_BROWSEPATH], /* .memberType */ + offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, browsePathsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* TranslateBrowsePathsToNodeIdsResponse */ +static UA_DataTypeMember TranslateBrowsePathsToNodeIdsResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_BROWSEPATHRESULT], /* .memberType */ + offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, resultsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, diagnosticInfosSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* RegisterNodesRequest */ +static UA_DataTypeMember RegisterNodesRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodesToRegister") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_RegisterNodesRequest, nodesToRegisterSize) - offsetof(UA_RegisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* RegisterNodesResponse */ +static UA_DataTypeMember RegisterNodesResponse_members[2] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RegisteredNodeIds") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_RegisterNodesResponse, registeredNodeIdsSize) - offsetof(UA_RegisterNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* UnregisterNodesRequest */ +static UA_DataTypeMember UnregisterNodesRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodesToUnregister") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_UnregisterNodesRequest, nodesToUnregisterSize) - offsetof(UA_UnregisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* UnregisterNodesResponse */ +static UA_DataTypeMember UnregisterNodesResponse_members[1] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* FilterOperator */ +#define FilterOperator_members NULL + +/* ContentFilterElement */ +static UA_DataTypeMember ContentFilterElement_members[2] = { +{ + UA_TYPENAME("FilterOperator") /* .memberName */ + &UA_TYPES[UA_TYPES_FILTEROPERATOR], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("FilterOperands") /* .memberName */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ + offsetof(UA_ContentFilterElement, filterOperandsSize) - offsetof(UA_ContentFilterElement, filterOperator) - sizeof(UA_FilterOperator), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* ContentFilter */ +static UA_DataTypeMember ContentFilter_members[1] = { +{ + UA_TYPENAME("Elements") /* .memberName */ + &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT], /* .memberType */ + 0, /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* ElementOperand */ +static UA_DataTypeMember ElementOperand_members[1] = { +{ + UA_TYPENAME("Index") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* LiteralOperand */ +static UA_DataTypeMember LiteralOperand_members[1] = { +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AttributeOperand */ +static UA_DataTypeMember AttributeOperand_members[5] = { +{ + UA_TYPENAME("NodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Alias") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_AttributeOperand, alias) - offsetof(UA_AttributeOperand, nodeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BrowsePath") /* .memberName */ + &UA_TYPES[UA_TYPES_RELATIVEPATH], /* .memberType */ + offsetof(UA_AttributeOperand, browsePath) - offsetof(UA_AttributeOperand, alias) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AttributeId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_AttributeOperand, attributeId) - offsetof(UA_AttributeOperand, browsePath) - sizeof(UA_RelativePath), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IndexRange") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_AttributeOperand, indexRange) - offsetof(UA_AttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* SimpleAttributeOperand */ +static UA_DataTypeMember SimpleAttributeOperand_members[4] = { +{ + UA_TYPENAME("TypeDefinitionId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BrowsePath") /* .memberName */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ + offsetof(UA_SimpleAttributeOperand, browsePathSize) - offsetof(UA_SimpleAttributeOperand, typeDefinitionId) - sizeof(UA_NodeId), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AttributeId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SimpleAttributeOperand, attributeId) - offsetof(UA_SimpleAttributeOperand, browsePath) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IndexRange") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_SimpleAttributeOperand, indexRange) - offsetof(UA_SimpleAttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ContentFilterElementResult */ +static UA_DataTypeMember ContentFilterElementResult_members[3] = { +{ + UA_TYPENAME("StatusCode") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("OperandStatusCodes") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_ContentFilterElementResult, operandStatusCodesSize) - offsetof(UA_ContentFilterElementResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("OperandDiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_ContentFilterElementResult, operandDiagnosticInfosSize) - offsetof(UA_ContentFilterElementResult, operandStatusCodes) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* ContentFilterResult */ +static UA_DataTypeMember ContentFilterResult_members[2] = { +{ + UA_TYPENAME("ElementResults") /* .memberName */ + &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT], /* .memberType */ + 0, /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ElementDiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_ContentFilterResult, elementDiagnosticInfosSize) - offsetof(UA_ContentFilterResult, elementResults) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* TimestampsToReturn */ +#define TimestampsToReturn_members NULL + +/* ReadValueId */ +static UA_DataTypeMember ReadValueId_members[4] = { +{ + UA_TYPENAME("NodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AttributeId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ReadValueId, attributeId) - offsetof(UA_ReadValueId, nodeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IndexRange") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_ReadValueId, indexRange) - offsetof(UA_ReadValueId, attributeId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DataEncoding") /* .memberName */ + &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */ + offsetof(UA_ReadValueId, dataEncoding) - offsetof(UA_ReadValueId, indexRange) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ReadRequest */ +static UA_DataTypeMember ReadRequest_members[4] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxAge") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_ReadRequest, maxAge) - offsetof(UA_ReadRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TimestampsToReturn") /* .memberName */ + &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */ + offsetof(UA_ReadRequest, timestampsToReturn) - offsetof(UA_ReadRequest, maxAge) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodesToRead") /* .memberName */ + &UA_TYPES[UA_TYPES_READVALUEID], /* .memberType */ + offsetof(UA_ReadRequest, nodesToReadSize) - offsetof(UA_ReadRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* ReadResponse */ +static UA_DataTypeMember ReadResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */ + offsetof(UA_ReadResponse, resultsSize) - offsetof(UA_ReadResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_ReadResponse, diagnosticInfosSize) - offsetof(UA_ReadResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* WriteValue */ +static UA_DataTypeMember WriteValue_members[4] = { +{ + UA_TYPENAME("NodeId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AttributeId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_WriteValue, attributeId) - offsetof(UA_WriteValue, nodeId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("IndexRange") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_WriteValue, indexRange) - offsetof(UA_WriteValue, attributeId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */ + offsetof(UA_WriteValue, value) - offsetof(UA_WriteValue, indexRange) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* WriteRequest */ +static UA_DataTypeMember WriteRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NodesToWrite") /* .memberName */ + &UA_TYPES[UA_TYPES_WRITEVALUE], /* .memberType */ + offsetof(UA_WriteRequest, nodesToWriteSize) - offsetof(UA_WriteRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* WriteResponse */ +static UA_DataTypeMember WriteResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_WriteResponse, resultsSize) - offsetof(UA_WriteResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_WriteResponse, diagnosticInfosSize) - offsetof(UA_WriteResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* CallMethodRequest */ +static UA_DataTypeMember CallMethodRequest_members[3] = { +{ + UA_TYPENAME("ObjectId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MethodId") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_CallMethodRequest, methodId) - offsetof(UA_CallMethodRequest, objectId) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("InputArguments") /* .memberName */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ + offsetof(UA_CallMethodRequest, inputArgumentsSize) - offsetof(UA_CallMethodRequest, methodId) - sizeof(UA_NodeId), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* CallMethodResult */ +static UA_DataTypeMember CallMethodResult_members[4] = { +{ + UA_TYPENAME("StatusCode") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("InputArgumentResults") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_CallMethodResult, inputArgumentResultsSize) - offsetof(UA_CallMethodResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("InputArgumentDiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfosSize) - offsetof(UA_CallMethodResult, inputArgumentResults) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("OutputArguments") /* .memberName */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ + offsetof(UA_CallMethodResult, outputArgumentsSize) - offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfos) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* CallRequest */ +static UA_DataTypeMember CallRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MethodsToCall") /* .memberName */ + &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], /* .memberType */ + offsetof(UA_CallRequest, methodsToCallSize) - offsetof(UA_CallRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* CallResponse */ +static UA_DataTypeMember CallResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_CALLMETHODRESULT], /* .memberType */ + offsetof(UA_CallResponse, resultsSize) - offsetof(UA_CallResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_CallResponse, diagnosticInfosSize) - offsetof(UA_CallResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* MonitoringMode */ +#define MonitoringMode_members NULL + +/* DataChangeTrigger */ +#define DataChangeTrigger_members NULL + +/* DeadbandType */ +#define DeadbandType_members NULL + +/* DataChangeFilter */ +static UA_DataTypeMember DataChangeFilter_members[3] = { +{ + UA_TYPENAME("Trigger") /* .memberName */ + &UA_TYPES[UA_TYPES_DATACHANGETRIGGER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DeadbandType") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_DataChangeFilter, deadbandType) - offsetof(UA_DataChangeFilter, trigger) - sizeof(UA_DataChangeTrigger), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DeadbandValue") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_DataChangeFilter, deadbandValue) - offsetof(UA_DataChangeFilter, deadbandType) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* EventFilter */ +static UA_DataTypeMember EventFilter_members[2] = { +{ + UA_TYPENAME("SelectClauses") /* .memberName */ + &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND], /* .memberType */ + 0, /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WhereClause") /* .memberName */ + &UA_TYPES[UA_TYPES_CONTENTFILTER], /* .memberType */ + offsetof(UA_EventFilter, whereClause) - offsetof(UA_EventFilter, selectClauses) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AggregateConfiguration */ +static UA_DataTypeMember AggregateConfiguration_members[5] = { +{ + UA_TYPENAME("UseServerCapabilitiesDefaults") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TreatUncertainAsBad") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - offsetof(UA_AggregateConfiguration, useServerCapabilitiesDefaults) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("PercentDataBad") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ + offsetof(UA_AggregateConfiguration, percentDataBad) - offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("PercentDataGood") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ + offsetof(UA_AggregateConfiguration, percentDataGood) - offsetof(UA_AggregateConfiguration, percentDataBad) - sizeof(UA_Byte), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UseSlopedExtrapolation") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_AggregateConfiguration, useSlopedExtrapolation) - offsetof(UA_AggregateConfiguration, percentDataGood) - sizeof(UA_Byte), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AggregateFilter */ +static UA_DataTypeMember AggregateFilter_members[4] = { +{ + UA_TYPENAME("StartTime") /* .memberName */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AggregateType") /* .memberName */ + &UA_TYPES[UA_TYPES_NODEID], /* .memberType */ + offsetof(UA_AggregateFilter, aggregateType) - offsetof(UA_AggregateFilter, startTime) - sizeof(UA_DateTime), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ProcessingInterval") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_AggregateFilter, processingInterval) - offsetof(UA_AggregateFilter, aggregateType) - sizeof(UA_NodeId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AggregateConfiguration") /* .memberName */ + &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], /* .memberType */ + offsetof(UA_AggregateFilter, aggregateConfiguration) - offsetof(UA_AggregateFilter, processingInterval) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* EventFilterResult */ +static UA_DataTypeMember EventFilterResult_members[3] = { +{ + UA_TYPENAME("SelectClauseResults") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SelectClauseDiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_EventFilterResult, selectClauseDiagnosticInfosSize) - offsetof(UA_EventFilterResult, selectClauseResults) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("WhereClauseResult") /* .memberName */ + &UA_TYPES[UA_TYPES_CONTENTFILTERRESULT], /* .memberType */ + offsetof(UA_EventFilterResult, whereClauseResult) - offsetof(UA_EventFilterResult, selectClauseDiagnosticInfos) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* MonitoringParameters */ +static UA_DataTypeMember MonitoringParameters_members[5] = { +{ + UA_TYPENAME("ClientHandle") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SamplingInterval") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_MonitoringParameters, samplingInterval) - offsetof(UA_MonitoringParameters, clientHandle) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Filter") /* .memberName */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ + offsetof(UA_MonitoringParameters, filter) - offsetof(UA_MonitoringParameters, samplingInterval) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("QueueSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_MonitoringParameters, queueSize) - offsetof(UA_MonitoringParameters, filter) - sizeof(UA_ExtensionObject), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiscardOldest") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_MonitoringParameters, discardOldest) - offsetof(UA_MonitoringParameters, queueSize) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* MonitoredItemCreateRequest */ +static UA_DataTypeMember MonitoredItemCreateRequest_members[3] = { +{ + UA_TYPENAME("ItemToMonitor") /* .memberName */ + &UA_TYPES[UA_TYPES_READVALUEID], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MonitoringMode") /* .memberName */ + &UA_TYPES[UA_TYPES_MONITORINGMODE], /* .memberType */ + offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - offsetof(UA_MonitoredItemCreateRequest, itemToMonitor) - sizeof(UA_ReadValueId), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedParameters") /* .memberName */ + &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], /* .memberType */ + offsetof(UA_MonitoredItemCreateRequest, requestedParameters) - offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* MonitoredItemCreateResult */ +static UA_DataTypeMember MonitoredItemCreateResult_members[5] = { +{ + UA_TYPENAME("StatusCode") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MonitoredItemId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - offsetof(UA_MonitoredItemCreateResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedSamplingInterval") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedQueueSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("FilterResult") /* .memberName */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ + offsetof(UA_MonitoredItemCreateResult, filterResult) - offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* CreateMonitoredItemsRequest */ +static UA_DataTypeMember CreateMonitoredItemsRequest_members[4] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - offsetof(UA_CreateMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TimestampsToReturn") /* .memberName */ + &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */ + offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ItemsToCreate") /* .memberName */ + &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST], /* .memberType */ + offsetof(UA_CreateMonitoredItemsRequest, itemsToCreateSize) - offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* CreateMonitoredItemsResponse */ +static UA_DataTypeMember CreateMonitoredItemsResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT], /* .memberType */ + offsetof(UA_CreateMonitoredItemsResponse, resultsSize) - offsetof(UA_CreateMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_CreateMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_CreateMonitoredItemsResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* MonitoredItemModifyRequest */ +static UA_DataTypeMember MonitoredItemModifyRequest_members[2] = { +{ + UA_TYPENAME("MonitoredItemId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedParameters") /* .memberName */ + &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], /* .memberType */ + offsetof(UA_MonitoredItemModifyRequest, requestedParameters) - offsetof(UA_MonitoredItemModifyRequest, monitoredItemId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* MonitoredItemModifyResult */ +static UA_DataTypeMember MonitoredItemModifyResult_members[4] = { +{ + UA_TYPENAME("StatusCode") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedSamplingInterval") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemModifyResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedQueueSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("FilterResult") /* .memberName */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ + offsetof(UA_MonitoredItemModifyResult, filterResult) - offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ModifyMonitoredItemsRequest */ +static UA_DataTypeMember ModifyMonitoredItemsRequest_members[4] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - offsetof(UA_ModifyMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TimestampsToReturn") /* .memberName */ + &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */ + offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ItemsToModify") /* .memberName */ + &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST], /* .memberType */ + offsetof(UA_ModifyMonitoredItemsRequest, itemsToModifySize) - offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* ModifyMonitoredItemsResponse */ +static UA_DataTypeMember ModifyMonitoredItemsResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT], /* .memberType */ + offsetof(UA_ModifyMonitoredItemsResponse, resultsSize) - offsetof(UA_ModifyMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_ModifyMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_ModifyMonitoredItemsResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* SetMonitoringModeRequest */ +static UA_DataTypeMember SetMonitoringModeRequest_members[4] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SetMonitoringModeRequest, subscriptionId) - offsetof(UA_SetMonitoringModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MonitoringMode") /* .memberName */ + &UA_TYPES[UA_TYPES_MONITORINGMODE], /* .memberType */ + offsetof(UA_SetMonitoringModeRequest, monitoringMode) - offsetof(UA_SetMonitoringModeRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MonitoredItemIds") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SetMonitoringModeRequest, monitoredItemIdsSize) - offsetof(UA_SetMonitoringModeRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* SetMonitoringModeResponse */ +static UA_DataTypeMember SetMonitoringModeResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_SetMonitoringModeResponse, resultsSize) - offsetof(UA_SetMonitoringModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_SetMonitoringModeResponse, diagnosticInfosSize) - offsetof(UA_SetMonitoringModeResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* SetTriggeringRequest */ +static UA_DataTypeMember SetTriggeringRequest_members[5] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SetTriggeringRequest, subscriptionId) - offsetof(UA_SetTriggeringRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("TriggeringItemId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SetTriggeringRequest, triggeringItemId) - offsetof(UA_SetTriggeringRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("LinksToAdd") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SetTriggeringRequest, linksToAddSize) - offsetof(UA_SetTriggeringRequest, triggeringItemId) - sizeof(UA_UInt32), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("LinksToRemove") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SetTriggeringRequest, linksToRemoveSize) - offsetof(UA_SetTriggeringRequest, linksToAdd) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* SetTriggeringResponse */ +static UA_DataTypeMember SetTriggeringResponse_members[5] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AddResults") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_SetTriggeringResponse, addResultsSize) - offsetof(UA_SetTriggeringResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AddDiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_SetTriggeringResponse, addDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, addResults) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RemoveResults") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_SetTriggeringResponse, removeResultsSize) - offsetof(UA_SetTriggeringResponse, addDiagnosticInfos) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RemoveDiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_SetTriggeringResponse, removeDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, removeResults) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteMonitoredItemsRequest */ +static UA_DataTypeMember DeleteMonitoredItemsRequest_members[3] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - offsetof(UA_DeleteMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MonitoredItemIds") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_DeleteMonitoredItemsRequest, monitoredItemIdsSize) - offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteMonitoredItemsResponse */ +static UA_DataTypeMember DeleteMonitoredItemsResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_DeleteMonitoredItemsResponse, resultsSize) - offsetof(UA_DeleteMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_DeleteMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_DeleteMonitoredItemsResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* CreateSubscriptionRequest */ +static UA_DataTypeMember CreateSubscriptionRequest_members[7] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedPublishingInterval") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - offsetof(UA_CreateSubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedLifetimeCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedMaxKeepAliveCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("PublishingEnabled") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Priority") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ + offsetof(UA_CreateSubscriptionRequest, priority) - offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* CreateSubscriptionResponse */ +static UA_DataTypeMember CreateSubscriptionResponse_members[5] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_CreateSubscriptionResponse, subscriptionId) - offsetof(UA_CreateSubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedPublishingInterval") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - offsetof(UA_CreateSubscriptionResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedLifetimeCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedMaxKeepAliveCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_CreateSubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ModifySubscriptionRequest */ +static UA_DataTypeMember ModifySubscriptionRequest_members[7] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ModifySubscriptionRequest, subscriptionId) - offsetof(UA_ModifySubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedPublishingInterval") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - offsetof(UA_ModifySubscriptionRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedLifetimeCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestedMaxKeepAliveCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Priority") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTE], /* .memberType */ + offsetof(UA_ModifySubscriptionRequest, priority) - offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ModifySubscriptionResponse */ +static UA_DataTypeMember ModifySubscriptionResponse_members[4] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedPublishingInterval") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - offsetof(UA_ModifySubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedLifetimeCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RevisedMaxKeepAliveCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ModifySubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* SetPublishingModeRequest */ +static UA_DataTypeMember SetPublishingModeRequest_members[3] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("PublishingEnabled") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_SetPublishingModeRequest, publishingEnabled) - offsetof(UA_SetPublishingModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionIds") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SetPublishingModeRequest, subscriptionIdsSize) - offsetof(UA_SetPublishingModeRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* SetPublishingModeResponse */ +static UA_DataTypeMember SetPublishingModeResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_SetPublishingModeResponse, resultsSize) - offsetof(UA_SetPublishingModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_SetPublishingModeResponse, diagnosticInfosSize) - offsetof(UA_SetPublishingModeResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* NotificationMessage */ +static UA_DataTypeMember NotificationMessage_members[3] = { +{ + UA_TYPENAME("SequenceNumber") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("PublishTime") /* .memberName */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ + offsetof(UA_NotificationMessage, publishTime) - offsetof(UA_NotificationMessage, sequenceNumber) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NotificationData") /* .memberName */ + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */ + offsetof(UA_NotificationMessage, notificationDataSize) - offsetof(UA_NotificationMessage, publishTime) - sizeof(UA_DateTime), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* MonitoredItemNotification */ +static UA_DataTypeMember MonitoredItemNotification_members[2] = { +{ + UA_TYPENAME("ClientHandle") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */ + offsetof(UA_MonitoredItemNotification, value) - offsetof(UA_MonitoredItemNotification, clientHandle) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* EventFieldList */ +static UA_DataTypeMember EventFieldList_members[2] = { +{ + UA_TYPENAME("ClientHandle") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EventFields") /* .memberName */ + &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */ + offsetof(UA_EventFieldList, eventFieldsSize) - offsetof(UA_EventFieldList, clientHandle) - sizeof(UA_UInt32), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* StatusChangeNotification */ +static UA_DataTypeMember StatusChangeNotification_members[2] = { +{ + UA_TYPENAME("Status") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfo") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_StatusChangeNotification, diagnosticInfo) - offsetof(UA_StatusChangeNotification, status) - sizeof(UA_StatusCode), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* SubscriptionAcknowledgement */ +static UA_DataTypeMember SubscriptionAcknowledgement_members[2] = { +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SequenceNumber") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SubscriptionAcknowledgement, sequenceNumber) - offsetof(UA_SubscriptionAcknowledgement, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* PublishRequest */ +static UA_DataTypeMember PublishRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionAcknowledgements") /* .memberName */ + &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT], /* .memberType */ + offsetof(UA_PublishRequest, subscriptionAcknowledgementsSize) - offsetof(UA_PublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* PublishResponse */ +static UA_DataTypeMember PublishResponse_members[7] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_PublishResponse, subscriptionId) - offsetof(UA_PublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AvailableSequenceNumbers") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_PublishResponse, availableSequenceNumbersSize) - offsetof(UA_PublishResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MoreNotifications") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_PublishResponse, moreNotifications) - offsetof(UA_PublishResponse, availableSequenceNumbers) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NotificationMessage") /* .memberName */ + &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], /* .memberType */ + offsetof(UA_PublishResponse, notificationMessage) - offsetof(UA_PublishResponse, moreNotifications) - sizeof(UA_Boolean), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_PublishResponse, resultsSize) - offsetof(UA_PublishResponse, notificationMessage) - sizeof(UA_NotificationMessage), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_PublishResponse, diagnosticInfosSize) - offsetof(UA_PublishResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* RepublishRequest */ +static UA_DataTypeMember RepublishRequest_members[3] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_RepublishRequest, subscriptionId) - offsetof(UA_RepublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RetransmitSequenceNumber") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_RepublishRequest, retransmitSequenceNumber) - offsetof(UA_RepublishRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* RepublishResponse */ +static UA_DataTypeMember RepublishResponse_members[2] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("NotificationMessage") /* .memberName */ + &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], /* .memberType */ + offsetof(UA_RepublishResponse, notificationMessage) - offsetof(UA_RepublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* TransferResult */ +static UA_DataTypeMember TransferResult_members[2] = { +{ + UA_TYPENAME("StatusCode") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AvailableSequenceNumbers") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TransferResult, availableSequenceNumbersSize) - offsetof(UA_TransferResult, statusCode) - sizeof(UA_StatusCode), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* TransferSubscriptionsRequest */ +static UA_DataTypeMember TransferSubscriptionsRequest_members[3] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionIds") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TransferSubscriptionsRequest, subscriptionIdsSize) - offsetof(UA_TransferSubscriptionsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SendInitialValues") /* .memberName */ + &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */ + offsetof(UA_TransferSubscriptionsRequest, sendInitialValues) - offsetof(UA_TransferSubscriptionsRequest, subscriptionIds) - sizeof(void *), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* TransferSubscriptionsResponse */ +static UA_DataTypeMember TransferSubscriptionsResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_TRANSFERRESULT], /* .memberType */ + offsetof(UA_TransferSubscriptionsResponse, resultsSize) - offsetof(UA_TransferSubscriptionsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_TransferSubscriptionsResponse, diagnosticInfosSize) - offsetof(UA_TransferSubscriptionsResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteSubscriptionsRequest */ +static UA_DataTypeMember DeleteSubscriptionsRequest_members[2] = { +{ + UA_TYPENAME("RequestHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SubscriptionIds") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_DeleteSubscriptionsRequest, subscriptionIdsSize) - offsetof(UA_DeleteSubscriptionsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* DeleteSubscriptionsResponse */ +static UA_DataTypeMember DeleteSubscriptionsResponse_members[3] = { +{ + UA_TYPENAME("ResponseHeader") /* .memberName */ + &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Results") /* .memberName */ + &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */ + offsetof(UA_DeleteSubscriptionsResponse, resultsSize) - offsetof(UA_DeleteSubscriptionsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_DeleteSubscriptionsResponse, diagnosticInfosSize) - offsetof(UA_DeleteSubscriptionsResponse, results) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* BuildInfo */ +static UA_DataTypeMember BuildInfo_members[6] = { +{ + UA_TYPENAME("ProductUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ManufacturerName") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_BuildInfo, manufacturerName) - offsetof(UA_BuildInfo, productUri) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ProductName") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_BuildInfo, productName) - offsetof(UA_BuildInfo, manufacturerName) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SoftwareVersion") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_BuildInfo, softwareVersion) - offsetof(UA_BuildInfo, productName) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BuildNumber") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_BuildInfo, buildNumber) - offsetof(UA_BuildInfo, softwareVersion) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BuildDate") /* .memberName */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ + offsetof(UA_BuildInfo, buildDate) - offsetof(UA_BuildInfo, buildNumber) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* RedundancySupport */ +#define RedundancySupport_members NULL + +/* ServerState */ +#define ServerState_members NULL + +/* ServerDiagnosticsSummaryDataType */ +static UA_DataTypeMember ServerDiagnosticsSummaryDataType_members[12] = { +{ + UA_TYPENAME("ServerViewCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("CurrentSessionCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, serverViewCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("CumulatedSessionCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SecurityRejectedSessionCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RejectedSessionCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SessionTimeoutCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SessionAbortCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("CurrentSubscriptionCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("CumulatedSubscriptionCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("PublishingIntervalCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SecurityRejectedRequestsCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RejectedRequestsCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* ServerStatusDataType */ +static UA_DataTypeMember ServerStatusDataType_members[6] = { +{ + UA_TYPENAME("StartTime") /* .memberName */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("CurrentTime") /* .memberName */ + &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */ + offsetof(UA_ServerStatusDataType, currentTime) - offsetof(UA_ServerStatusDataType, startTime) - sizeof(UA_DateTime), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("State") /* .memberName */ + &UA_TYPES[UA_TYPES_SERVERSTATE], /* .memberType */ + offsetof(UA_ServerStatusDataType, state) - offsetof(UA_ServerStatusDataType, currentTime) - sizeof(UA_DateTime), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("BuildInfo") /* .memberName */ + &UA_TYPES[UA_TYPES_BUILDINFO], /* .memberType */ + offsetof(UA_ServerStatusDataType, buildInfo) - offsetof(UA_ServerStatusDataType, state) - sizeof(UA_ServerState), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SecondsTillShutdown") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_ServerStatusDataType, secondsTillShutdown) - offsetof(UA_ServerStatusDataType, buildInfo) - sizeof(UA_BuildInfo), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ShutdownReason") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_ServerStatusDataType, shutdownReason) - offsetof(UA_ServerStatusDataType, secondsTillShutdown) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* Range */ +static UA_DataTypeMember Range_members[2] = { +{ + UA_TYPENAME("Low") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("High") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_Range, high) - offsetof(UA_Range, low) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* EUInformation */ +static UA_DataTypeMember EUInformation_members[4] = { +{ + UA_TYPENAME("NamespaceUri") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("UnitId") /* .memberName */ + &UA_TYPES[UA_TYPES_INT32], /* .memberType */ + offsetof(UA_EUInformation, unitId) - offsetof(UA_EUInformation, namespaceUri) - sizeof(UA_String), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DisplayName") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_EUInformation, displayName) - offsetof(UA_EUInformation, unitId) - sizeof(UA_Int32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Description") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_EUInformation, description) - offsetof(UA_EUInformation, displayName) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AxisScaleEnumeration */ +#define AxisScaleEnumeration_members NULL + +/* ComplexNumberType */ +static UA_DataTypeMember ComplexNumberType_members[2] = { +{ + UA_TYPENAME("Real") /* .memberName */ + &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Imaginary") /* .memberName */ + &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */ + offsetof(UA_ComplexNumberType, imaginary) - offsetof(UA_ComplexNumberType, real) - sizeof(UA_Float), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* DoubleComplexNumberType */ +static UA_DataTypeMember DoubleComplexNumberType_members[2] = { +{ + UA_TYPENAME("Real") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Imaginary") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_DoubleComplexNumberType, imaginary) - offsetof(UA_DoubleComplexNumberType, real) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AxisInformation */ +static UA_DataTypeMember AxisInformation_members[5] = { +{ + UA_TYPENAME("EngineeringUnits") /* .memberName */ + &UA_TYPES[UA_TYPES_EUINFORMATION], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EURange") /* .memberName */ + &UA_TYPES[UA_TYPES_RANGE], /* .memberType */ + offsetof(UA_AxisInformation, eURange) - offsetof(UA_AxisInformation, engineeringUnits) - sizeof(UA_EUInformation), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Title") /* .memberName */ + &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */ + offsetof(UA_AxisInformation, title) - offsetof(UA_AxisInformation, eURange) - sizeof(UA_Range), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AxisScaleType") /* .memberName */ + &UA_TYPES[UA_TYPES_AXISSCALEENUMERATION], /* .memberType */ + offsetof(UA_AxisInformation, axisScaleType) - offsetof(UA_AxisInformation, title) - sizeof(UA_LocalizedText), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("AxisSteps") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + offsetof(UA_AxisInformation, axisStepsSize) - offsetof(UA_AxisInformation, axisScaleType) - sizeof(UA_AxisScaleEnumeration), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* XVType */ +static UA_DataTypeMember XVType_members[2] = { +{ + UA_TYPENAME("X") /* .memberName */ + &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Value") /* .memberName */ + &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */ + offsetof(UA_XVType, value) - offsetof(UA_XVType, x) - sizeof(UA_Double), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* EnumDefinition */ +static UA_DataTypeMember EnumDefinition_members[1] = { +{ + UA_TYPENAME("Fields") /* .memberName */ + &UA_TYPES[UA_TYPES_ENUMFIELD], /* .memberType */ + 0, /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* DataChangeNotification */ +static UA_DataTypeMember DataChangeNotification_members[2] = { +{ + UA_TYPENAME("MonitoredItems") /* .memberName */ + &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION], /* .memberType */ + 0, /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("DiagnosticInfos") /* .memberName */ + &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */ + offsetof(UA_DataChangeNotification, diagnosticInfosSize) - offsetof(UA_DataChangeNotification, monitoredItems) - sizeof(void *), /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; + +/* EventNotificationList */ +static UA_DataTypeMember EventNotificationList_members[1] = { +{ + UA_TYPENAME("Events") /* .memberName */ + &UA_TYPES[UA_TYPES_EVENTFIELDLIST], /* .memberType */ + 0, /* .padding */ + true, /* .isArray */ + false /* .isOptional */ +},}; +const UA_DataType UA_TYPES[UA_TYPES_COUNT] = { +/* Boolean */ +{ + UA_TYPENAME("Boolean") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {1LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Boolean), /* .memSize */ + UA_DATATYPEKIND_BOOLEAN, /* .typeKind */ + true, /* .pointerFree */ + true, /* .overlayable */ + 0, /* .membersSize */ + Boolean_members /* .members */ +}, +/* SByte */ +{ + UA_TYPENAME("SByte") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {2LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_SByte), /* .memSize */ + UA_DATATYPEKIND_SBYTE, /* .typeKind */ + true, /* .pointerFree */ + true, /* .overlayable */ + 0, /* .membersSize */ + SByte_members /* .members */ +}, +/* Byte */ +{ + UA_TYPENAME("Byte") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {3LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Byte), /* .memSize */ + UA_DATATYPEKIND_BYTE, /* .typeKind */ + true, /* .pointerFree */ + true, /* .overlayable */ + 0, /* .membersSize */ + Byte_members /* .members */ +}, +/* Int16 */ +{ + UA_TYPENAME("Int16") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {4LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Int16), /* .memSize */ + UA_DATATYPEKIND_INT16, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + Int16_members /* .members */ +}, +/* UInt16 */ +{ + UA_TYPENAME("UInt16") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {5LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_UInt16), /* .memSize */ + UA_DATATYPEKIND_UINT16, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + UInt16_members /* .members */ +}, +/* Int32 */ +{ + UA_TYPENAME("Int32") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {6LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Int32), /* .memSize */ + UA_DATATYPEKIND_INT32, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + Int32_members /* .members */ +}, +/* UInt32 */ +{ + UA_TYPENAME("UInt32") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {7LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_UInt32), /* .memSize */ + UA_DATATYPEKIND_UINT32, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + UInt32_members /* .members */ +}, +/* Int64 */ +{ + UA_TYPENAME("Int64") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {8LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Int64), /* .memSize */ + UA_DATATYPEKIND_INT64, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + Int64_members /* .members */ +}, +/* UInt64 */ +{ + UA_TYPENAME("UInt64") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {9LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_UInt64), /* .memSize */ + UA_DATATYPEKIND_UINT64, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + UInt64_members /* .members */ +}, +/* Float */ +{ + UA_TYPENAME("Float") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {10LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Float), /* .memSize */ + UA_DATATYPEKIND_FLOAT, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */ + 0, /* .membersSize */ + Float_members /* .members */ +}, +/* Double */ +{ + UA_TYPENAME("Double") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {11LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Double), /* .memSize */ + UA_DATATYPEKIND_DOUBLE, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */ + 0, /* .membersSize */ + Double_members /* .members */ +}, +/* String */ +{ + UA_TYPENAME("String") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_String), /* .memSize */ + UA_DATATYPEKIND_STRING, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + String_members /* .members */ +}, +/* DateTime */ +{ + UA_TYPENAME("DateTime") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {13LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_DateTime), /* .memSize */ + UA_DATATYPEKIND_DATETIME, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + DateTime_members /* .members */ +}, +/* Guid */ +{ + UA_TYPENAME("Guid") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {14LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Guid), /* .memSize */ + UA_DATATYPEKIND_GUID, /* .typeKind */ + true, /* .pointerFree */ + (UA_BINARY_OVERLAYABLE_INTEGER && offsetof(UA_Guid, data2) == sizeof(UA_UInt32) && offsetof(UA_Guid, data3) == (sizeof(UA_UInt16) + sizeof(UA_UInt32)) && offsetof(UA_Guid, data4) == (2*sizeof(UA_UInt32))), /* .overlayable */ + 0, /* .membersSize */ + Guid_members /* .members */ +}, +/* ByteString */ +{ + UA_TYPENAME("ByteString") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {15LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_ByteString), /* .memSize */ + UA_DATATYPEKIND_BYTESTRING, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + ByteString_members /* .members */ +}, +/* XmlElement */ +{ + UA_TYPENAME("XmlElement") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {16LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_XmlElement), /* .memSize */ + UA_DATATYPEKIND_XMLELEMENT, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + XmlElement_members /* .members */ +}, +/* NodeId */ +{ + UA_TYPENAME("NodeId") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {17LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_NodeId), /* .memSize */ + UA_DATATYPEKIND_NODEID, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + NodeId_members /* .members */ +}, +/* ExpandedNodeId */ +{ + UA_TYPENAME("ExpandedNodeId") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {18LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_ExpandedNodeId), /* .memSize */ + UA_DATATYPEKIND_EXPANDEDNODEID, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + ExpandedNodeId_members /* .members */ +}, +/* StatusCode */ +{ + UA_TYPENAME("StatusCode") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {19LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_StatusCode), /* .memSize */ + UA_DATATYPEKIND_STATUSCODE, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + StatusCode_members /* .members */ +}, +/* QualifiedName */ +{ + UA_TYPENAME("QualifiedName") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {20LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_QualifiedName), /* .memSize */ + UA_DATATYPEKIND_QUALIFIEDNAME, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + QualifiedName_members /* .members */ +}, +/* LocalizedText */ +{ + UA_TYPENAME("LocalizedText") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {21LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_LocalizedText), /* .memSize */ + UA_DATATYPEKIND_LOCALIZEDTEXT, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + LocalizedText_members /* .members */ +}, +/* ExtensionObject */ +{ + UA_TYPENAME("ExtensionObject") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {22LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_ExtensionObject), /* .memSize */ + UA_DATATYPEKIND_EXTENSIONOBJECT, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + ExtensionObject_members /* .members */ +}, +/* DataValue */ +{ + UA_TYPENAME("DataValue") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {23LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_DataValue), /* .memSize */ + UA_DATATYPEKIND_DATAVALUE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + DataValue_members /* .members */ +}, +/* Variant */ +{ + UA_TYPENAME("Variant") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {24LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Variant), /* .memSize */ + UA_DATATYPEKIND_VARIANT, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + Variant_members /* .members */ +}, +/* DiagnosticInfo */ +{ + UA_TYPENAME("DiagnosticInfo") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {25LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_DiagnosticInfo), /* .memSize */ + UA_DATATYPEKIND_DIAGNOSTICINFO, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + DiagnosticInfo_members /* .members */ +}, +/* KeyValuePair */ +{ + UA_TYPENAME("KeyValuePair") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {14533LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {14846LU}}, /* .binaryEncodingId */ + sizeof(UA_KeyValuePair), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + KeyValuePair_members /* .members */ +}, +/* NodeClass */ +{ + UA_TYPENAME("NodeClass") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {257LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_NodeClass), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + NodeClass_members /* .members */ +}, +/* StructureType */ +{ + UA_TYPENAME("StructureType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {98LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_StructureType), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + StructureType_members /* .members */ +}, +/* StructureField */ +{ + UA_TYPENAME("StructureField") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {101LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {14844LU}}, /* .binaryEncodingId */ + sizeof(UA_StructureField), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + StructureField_members /* .members */ +}, +/* StructureDefinition */ +{ + UA_TYPENAME("StructureDefinition") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {99LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {122LU}}, /* .binaryEncodingId */ + sizeof(UA_StructureDefinition), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + StructureDefinition_members /* .members */ +}, +/* Argument */ +{ + UA_TYPENAME("Argument") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {296LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {298LU}}, /* .binaryEncodingId */ + sizeof(UA_Argument), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + Argument_members /* .members */ +}, +/* EnumValueType */ +{ + UA_TYPENAME("EnumValueType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {7594LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {8251LU}}, /* .binaryEncodingId */ + sizeof(UA_EnumValueType), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + EnumValueType_members /* .members */ +}, +/* EnumField */ +{ + UA_TYPENAME("EnumField") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {102LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {14845LU}}, /* .binaryEncodingId */ + sizeof(UA_EnumField), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + EnumField_members /* .members */ +}, +/* Duration */ +{ + UA_TYPENAME("Duration") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {290LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_Duration), /* .memSize */ + UA_DATATYPEKIND_DOUBLE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + Duration_members /* .members */ +}, +/* UtcTime */ +{ + UA_TYPENAME("UtcTime") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {294LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_UtcTime), /* .memSize */ + UA_DATATYPEKIND_DATETIME, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + UtcTime_members /* .members */ +}, +/* LocaleId */ +{ + UA_TYPENAME("LocaleId") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {295LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_LocaleId), /* .memSize */ + UA_DATATYPEKIND_STRING, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 0, /* .membersSize */ + LocaleId_members /* .members */ +}, +/* TimeZoneDataType */ +{ + UA_TYPENAME("TimeZoneDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {8912LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {8917LU}}, /* .binaryEncodingId */ + sizeof(UA_TimeZoneDataType), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + TimeZoneDataType_members /* .members */ +}, +/* ApplicationType */ +{ + UA_TYPENAME("ApplicationType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {307LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_ApplicationType), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + ApplicationType_members /* .members */ +}, +/* ApplicationDescription */ +{ + UA_TYPENAME("ApplicationDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {308LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {310LU}}, /* .binaryEncodingId */ + sizeof(UA_ApplicationDescription), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + ApplicationDescription_members /* .members */ +}, +/* RequestHeader */ +{ + UA_TYPENAME("RequestHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {389LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {391LU}}, /* .binaryEncodingId */ + sizeof(UA_RequestHeader), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + RequestHeader_members /* .members */ +}, +/* ResponseHeader */ +{ + UA_TYPENAME("ResponseHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {392LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {394LU}}, /* .binaryEncodingId */ + sizeof(UA_ResponseHeader), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + ResponseHeader_members /* .members */ +}, +/* ServiceFault */ +{ + UA_TYPENAME("ServiceFault") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {395LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {397LU}}, /* .binaryEncodingId */ + sizeof(UA_ServiceFault), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + ServiceFault_members /* .members */ +}, +/* FindServersRequest */ +{ + UA_TYPENAME("FindServersRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {420LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {422LU}}, /* .binaryEncodingId */ + sizeof(UA_FindServersRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + FindServersRequest_members /* .members */ +}, +/* FindServersResponse */ +{ + UA_TYPENAME("FindServersResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {423LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {425LU}}, /* .binaryEncodingId */ + sizeof(UA_FindServersResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + FindServersResponse_members /* .members */ +}, +/* MessageSecurityMode */ +{ + UA_TYPENAME("MessageSecurityMode") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {302LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_MessageSecurityMode), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + MessageSecurityMode_members /* .members */ +}, +/* UserTokenType */ +{ + UA_TYPENAME("UserTokenType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {303LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_UserTokenType), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + UserTokenType_members /* .members */ +}, +/* UserTokenPolicy */ +{ + UA_TYPENAME("UserTokenPolicy") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {304LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {306LU}}, /* .binaryEncodingId */ + sizeof(UA_UserTokenPolicy), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + UserTokenPolicy_members /* .members */ +}, +/* EndpointDescription */ +{ + UA_TYPENAME("EndpointDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {312LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {314LU}}, /* .binaryEncodingId */ + sizeof(UA_EndpointDescription), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 8, /* .membersSize */ + EndpointDescription_members /* .members */ +}, +/* GetEndpointsRequest */ +{ + UA_TYPENAME("GetEndpointsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {426LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {428LU}}, /* .binaryEncodingId */ + sizeof(UA_GetEndpointsRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + GetEndpointsRequest_members /* .members */ +}, +/* GetEndpointsResponse */ +{ + UA_TYPENAME("GetEndpointsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {429LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {431LU}}, /* .binaryEncodingId */ + sizeof(UA_GetEndpointsResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + GetEndpointsResponse_members /* .members */ +}, +/* SecurityTokenRequestType */ +{ + UA_TYPENAME("SecurityTokenRequestType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {315LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_SecurityTokenRequestType), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + SecurityTokenRequestType_members /* .members */ +}, +/* ChannelSecurityToken */ +{ + UA_TYPENAME("ChannelSecurityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {441LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {443LU}}, /* .binaryEncodingId */ + sizeof(UA_ChannelSecurityToken), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + ChannelSecurityToken_members /* .members */ +}, +/* OpenSecureChannelRequest */ +{ + UA_TYPENAME("OpenSecureChannelRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {444LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {446LU}}, /* .binaryEncodingId */ + sizeof(UA_OpenSecureChannelRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + OpenSecureChannelRequest_members /* .members */ +}, +/* OpenSecureChannelResponse */ +{ + UA_TYPENAME("OpenSecureChannelResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {447LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {449LU}}, /* .binaryEncodingId */ + sizeof(UA_OpenSecureChannelResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + OpenSecureChannelResponse_members /* .members */ +}, +/* CloseSecureChannelRequest */ +{ + UA_TYPENAME("CloseSecureChannelRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {450LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {452LU}}, /* .binaryEncodingId */ + sizeof(UA_CloseSecureChannelRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + CloseSecureChannelRequest_members /* .members */ +}, +/* CloseSecureChannelResponse */ +{ + UA_TYPENAME("CloseSecureChannelResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {453LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {455LU}}, /* .binaryEncodingId */ + sizeof(UA_CloseSecureChannelResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + CloseSecureChannelResponse_members /* .members */ +}, +/* SignedSoftwareCertificate */ +{ + UA_TYPENAME("SignedSoftwareCertificate") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {344LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {346LU}}, /* .binaryEncodingId */ + sizeof(UA_SignedSoftwareCertificate), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + SignedSoftwareCertificate_members /* .members */ +}, +/* SignatureData */ +{ + UA_TYPENAME("SignatureData") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {456LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {458LU}}, /* .binaryEncodingId */ + sizeof(UA_SignatureData), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + SignatureData_members /* .members */ +}, +/* CreateSessionRequest */ +{ + UA_TYPENAME("CreateSessionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {459LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {461LU}}, /* .binaryEncodingId */ + sizeof(UA_CreateSessionRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 9, /* .membersSize */ + CreateSessionRequest_members /* .members */ +}, +/* CreateSessionResponse */ +{ + UA_TYPENAME("CreateSessionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {462LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {464LU}}, /* .binaryEncodingId */ + sizeof(UA_CreateSessionResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 10, /* .membersSize */ + CreateSessionResponse_members /* .members */ +}, +/* UserIdentityToken */ +{ + UA_TYPENAME("UserIdentityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {316LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {318LU}}, /* .binaryEncodingId */ + sizeof(UA_UserIdentityToken), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + UserIdentityToken_members /* .members */ +}, +/* AnonymousIdentityToken */ +{ + UA_TYPENAME("AnonymousIdentityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {319LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {321LU}}, /* .binaryEncodingId */ + sizeof(UA_AnonymousIdentityToken), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + AnonymousIdentityToken_members /* .members */ +}, +/* UserNameIdentityToken */ +{ + UA_TYPENAME("UserNameIdentityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {322LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {324LU}}, /* .binaryEncodingId */ + sizeof(UA_UserNameIdentityToken), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + UserNameIdentityToken_members /* .members */ +}, +/* X509IdentityToken */ +{ + UA_TYPENAME("X509IdentityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {325LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {327LU}}, /* .binaryEncodingId */ + sizeof(UA_X509IdentityToken), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + X509IdentityToken_members /* .members */ +}, +/* IssuedIdentityToken */ +{ + UA_TYPENAME("IssuedIdentityToken") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {938LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {940LU}}, /* .binaryEncodingId */ + sizeof(UA_IssuedIdentityToken), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + IssuedIdentityToken_members /* .members */ +}, +/* ActivateSessionRequest */ +{ + UA_TYPENAME("ActivateSessionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {465LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {467LU}}, /* .binaryEncodingId */ + sizeof(UA_ActivateSessionRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + ActivateSessionRequest_members /* .members */ +}, +/* ActivateSessionResponse */ +{ + UA_TYPENAME("ActivateSessionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {468LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {470LU}}, /* .binaryEncodingId */ + sizeof(UA_ActivateSessionResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + ActivateSessionResponse_members /* .members */ +}, +/* CloseSessionRequest */ +{ + UA_TYPENAME("CloseSessionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {471LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {473LU}}, /* .binaryEncodingId */ + sizeof(UA_CloseSessionRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + CloseSessionRequest_members /* .members */ +}, +/* CloseSessionResponse */ +{ + UA_TYPENAME("CloseSessionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {474LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {476LU}}, /* .binaryEncodingId */ + sizeof(UA_CloseSessionResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + CloseSessionResponse_members /* .members */ +}, +/* NodeAttributesMask */ +{ + UA_TYPENAME("NodeAttributesMask") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {348LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_NodeAttributesMask), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + NodeAttributesMask_members /* .members */ +}, +/* NodeAttributes */ +{ + UA_TYPENAME("NodeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {349LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {351LU}}, /* .binaryEncodingId */ + sizeof(UA_NodeAttributes), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + NodeAttributes_members /* .members */ +}, +/* ObjectAttributes */ +{ + UA_TYPENAME("ObjectAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {352LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {354LU}}, /* .binaryEncodingId */ + sizeof(UA_ObjectAttributes), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + ObjectAttributes_members /* .members */ +}, +/* VariableAttributes */ +{ + UA_TYPENAME("VariableAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {355LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {357LU}}, /* .binaryEncodingId */ + sizeof(UA_VariableAttributes), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 13, /* .membersSize */ + VariableAttributes_members /* .members */ +}, +/* MethodAttributes */ +{ + UA_TYPENAME("MethodAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {358LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {360LU}}, /* .binaryEncodingId */ + sizeof(UA_MethodAttributes), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + MethodAttributes_members /* .members */ +}, +/* ObjectTypeAttributes */ +{ + UA_TYPENAME("ObjectTypeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {361LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {363LU}}, /* .binaryEncodingId */ + sizeof(UA_ObjectTypeAttributes), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + ObjectTypeAttributes_members /* .members */ +}, +/* VariableTypeAttributes */ +{ + UA_TYPENAME("VariableTypeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {364LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {366LU}}, /* .binaryEncodingId */ + sizeof(UA_VariableTypeAttributes), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 10, /* .membersSize */ + VariableTypeAttributes_members /* .members */ +}, +/* ReferenceTypeAttributes */ +{ + UA_TYPENAME("ReferenceTypeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {367LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {369LU}}, /* .binaryEncodingId */ + sizeof(UA_ReferenceTypeAttributes), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 8, /* .membersSize */ + ReferenceTypeAttributes_members /* .members */ +}, +/* DataTypeAttributes */ +{ + UA_TYPENAME("DataTypeAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {370LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {372LU}}, /* .binaryEncodingId */ + sizeof(UA_DataTypeAttributes), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + DataTypeAttributes_members /* .members */ +}, +/* ViewAttributes */ +{ + UA_TYPENAME("ViewAttributes") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {373LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {375LU}}, /* .binaryEncodingId */ + sizeof(UA_ViewAttributes), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + ViewAttributes_members /* .members */ +}, +/* AddNodesItem */ +{ + UA_TYPENAME("AddNodesItem") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {376LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {378LU}}, /* .binaryEncodingId */ + sizeof(UA_AddNodesItem), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + AddNodesItem_members /* .members */ +}, +/* AddNodesResult */ +{ + UA_TYPENAME("AddNodesResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {483LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {485LU}}, /* .binaryEncodingId */ + sizeof(UA_AddNodesResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + AddNodesResult_members /* .members */ +}, +/* AddNodesRequest */ +{ + UA_TYPENAME("AddNodesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {486LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {488LU}}, /* .binaryEncodingId */ + sizeof(UA_AddNodesRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + AddNodesRequest_members /* .members */ +}, +/* AddNodesResponse */ +{ + UA_TYPENAME("AddNodesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {489LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {491LU}}, /* .binaryEncodingId */ + sizeof(UA_AddNodesResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + AddNodesResponse_members /* .members */ +}, +/* AddReferencesItem */ +{ + UA_TYPENAME("AddReferencesItem") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {379LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {381LU}}, /* .binaryEncodingId */ + sizeof(UA_AddReferencesItem), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + AddReferencesItem_members /* .members */ +}, +/* AddReferencesRequest */ +{ + UA_TYPENAME("AddReferencesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {492LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {494LU}}, /* .binaryEncodingId */ + sizeof(UA_AddReferencesRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + AddReferencesRequest_members /* .members */ +}, +/* AddReferencesResponse */ +{ + UA_TYPENAME("AddReferencesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {495LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {497LU}}, /* .binaryEncodingId */ + sizeof(UA_AddReferencesResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + AddReferencesResponse_members /* .members */ +}, +/* DeleteNodesItem */ +{ + UA_TYPENAME("DeleteNodesItem") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {382LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {384LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteNodesItem), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + DeleteNodesItem_members /* .members */ +}, +/* DeleteNodesRequest */ +{ + UA_TYPENAME("DeleteNodesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {498LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {500LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteNodesRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + DeleteNodesRequest_members /* .members */ +}, +/* DeleteNodesResponse */ +{ + UA_TYPENAME("DeleteNodesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {501LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {503LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteNodesResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + DeleteNodesResponse_members /* .members */ +}, +/* DeleteReferencesItem */ +{ + UA_TYPENAME("DeleteReferencesItem") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {385LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {387LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteReferencesItem), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + DeleteReferencesItem_members /* .members */ +}, +/* DeleteReferencesRequest */ +{ + UA_TYPENAME("DeleteReferencesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {504LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {506LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteReferencesRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + DeleteReferencesRequest_members /* .members */ +}, +/* DeleteReferencesResponse */ +{ + UA_TYPENAME("DeleteReferencesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {507LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {509LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteReferencesResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + DeleteReferencesResponse_members /* .members */ +}, +/* BrowseDirection */ +{ + UA_TYPENAME("BrowseDirection") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {510LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_BrowseDirection), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + BrowseDirection_members /* .members */ +}, +/* ViewDescription */ +{ + UA_TYPENAME("ViewDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {511LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {513LU}}, /* .binaryEncodingId */ + sizeof(UA_ViewDescription), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + ViewDescription_members /* .members */ +}, +/* BrowseDescription */ +{ + UA_TYPENAME("BrowseDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {514LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {516LU}}, /* .binaryEncodingId */ + sizeof(UA_BrowseDescription), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + BrowseDescription_members /* .members */ +}, +/* BrowseResultMask */ +{ + UA_TYPENAME("BrowseResultMask") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {517LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_BrowseResultMask), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + BrowseResultMask_members /* .members */ +}, +/* ReferenceDescription */ +{ + UA_TYPENAME("ReferenceDescription") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {518LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {520LU}}, /* .binaryEncodingId */ + sizeof(UA_ReferenceDescription), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + ReferenceDescription_members /* .members */ +}, +/* BrowseResult */ +{ + UA_TYPENAME("BrowseResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {522LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {524LU}}, /* .binaryEncodingId */ + sizeof(UA_BrowseResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + BrowseResult_members /* .members */ +}, +/* BrowseRequest */ +{ + UA_TYPENAME("BrowseRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {525LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {527LU}}, /* .binaryEncodingId */ + sizeof(UA_BrowseRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + BrowseRequest_members /* .members */ +}, +/* BrowseResponse */ +{ + UA_TYPENAME("BrowseResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {528LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {530LU}}, /* .binaryEncodingId */ + sizeof(UA_BrowseResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + BrowseResponse_members /* .members */ +}, +/* BrowseNextRequest */ +{ + UA_TYPENAME("BrowseNextRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {531LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {533LU}}, /* .binaryEncodingId */ + sizeof(UA_BrowseNextRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + BrowseNextRequest_members /* .members */ +}, +/* BrowseNextResponse */ +{ + UA_TYPENAME("BrowseNextResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {534LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {536LU}}, /* .binaryEncodingId */ + sizeof(UA_BrowseNextResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + BrowseNextResponse_members /* .members */ +}, +/* RelativePathElement */ +{ + UA_TYPENAME("RelativePathElement") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {537LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {539LU}}, /* .binaryEncodingId */ + sizeof(UA_RelativePathElement), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + RelativePathElement_members /* .members */ +}, +/* RelativePath */ +{ + UA_TYPENAME("RelativePath") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {540LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {542LU}}, /* .binaryEncodingId */ + sizeof(UA_RelativePath), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + RelativePath_members /* .members */ +}, +/* BrowsePath */ +{ + UA_TYPENAME("BrowsePath") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {543LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {545LU}}, /* .binaryEncodingId */ + sizeof(UA_BrowsePath), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + BrowsePath_members /* .members */ +}, +/* BrowsePathTarget */ +{ + UA_TYPENAME("BrowsePathTarget") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {546LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {548LU}}, /* .binaryEncodingId */ + sizeof(UA_BrowsePathTarget), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + BrowsePathTarget_members /* .members */ +}, +/* BrowsePathResult */ +{ + UA_TYPENAME("BrowsePathResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {549LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {551LU}}, /* .binaryEncodingId */ + sizeof(UA_BrowsePathResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + BrowsePathResult_members /* .members */ +}, +/* TranslateBrowsePathsToNodeIdsRequest */ +{ + UA_TYPENAME("TranslateBrowsePathsToNodeIdsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {552LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {554LU}}, /* .binaryEncodingId */ + sizeof(UA_TranslateBrowsePathsToNodeIdsRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + TranslateBrowsePathsToNodeIdsRequest_members /* .members */ +}, +/* TranslateBrowsePathsToNodeIdsResponse */ +{ + UA_TYPENAME("TranslateBrowsePathsToNodeIdsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {555LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {557LU}}, /* .binaryEncodingId */ + sizeof(UA_TranslateBrowsePathsToNodeIdsResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + TranslateBrowsePathsToNodeIdsResponse_members /* .members */ +}, +/* RegisterNodesRequest */ +{ + UA_TYPENAME("RegisterNodesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {558LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {560LU}}, /* .binaryEncodingId */ + sizeof(UA_RegisterNodesRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + RegisterNodesRequest_members /* .members */ +}, +/* RegisterNodesResponse */ +{ + UA_TYPENAME("RegisterNodesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {561LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {563LU}}, /* .binaryEncodingId */ + sizeof(UA_RegisterNodesResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + RegisterNodesResponse_members /* .members */ +}, +/* UnregisterNodesRequest */ +{ + UA_TYPENAME("UnregisterNodesRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {564LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {566LU}}, /* .binaryEncodingId */ + sizeof(UA_UnregisterNodesRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + UnregisterNodesRequest_members /* .members */ +}, +/* UnregisterNodesResponse */ +{ + UA_TYPENAME("UnregisterNodesResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {567LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {569LU}}, /* .binaryEncodingId */ + sizeof(UA_UnregisterNodesResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + UnregisterNodesResponse_members /* .members */ +}, +/* FilterOperator */ +{ + UA_TYPENAME("FilterOperator") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {576LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_FilterOperator), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + FilterOperator_members /* .members */ +}, +/* ContentFilterElement */ +{ + UA_TYPENAME("ContentFilterElement") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {583LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {585LU}}, /* .binaryEncodingId */ + sizeof(UA_ContentFilterElement), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + ContentFilterElement_members /* .members */ +}, +/* ContentFilter */ +{ + UA_TYPENAME("ContentFilter") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {586LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {588LU}}, /* .binaryEncodingId */ + sizeof(UA_ContentFilter), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + ContentFilter_members /* .members */ +}, +/* ElementOperand */ +{ + UA_TYPENAME("ElementOperand") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {592LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {594LU}}, /* .binaryEncodingId */ + sizeof(UA_ElementOperand), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + ElementOperand_members /* .members */ +}, +/* LiteralOperand */ +{ + UA_TYPENAME("LiteralOperand") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {595LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {597LU}}, /* .binaryEncodingId */ + sizeof(UA_LiteralOperand), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + LiteralOperand_members /* .members */ +}, +/* AttributeOperand */ +{ + UA_TYPENAME("AttributeOperand") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {598LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {600LU}}, /* .binaryEncodingId */ + sizeof(UA_AttributeOperand), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + AttributeOperand_members /* .members */ +}, +/* SimpleAttributeOperand */ +{ + UA_TYPENAME("SimpleAttributeOperand") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {601LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {603LU}}, /* .binaryEncodingId */ + sizeof(UA_SimpleAttributeOperand), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + SimpleAttributeOperand_members /* .members */ +}, +/* ContentFilterElementResult */ +{ + UA_TYPENAME("ContentFilterElementResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {604LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {606LU}}, /* .binaryEncodingId */ + sizeof(UA_ContentFilterElementResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + ContentFilterElementResult_members /* .members */ +}, +/* ContentFilterResult */ +{ + UA_TYPENAME("ContentFilterResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {607LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {609LU}}, /* .binaryEncodingId */ + sizeof(UA_ContentFilterResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + ContentFilterResult_members /* .members */ +}, +/* TimestampsToReturn */ +{ + UA_TYPENAME("TimestampsToReturn") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {625LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_TimestampsToReturn), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + TimestampsToReturn_members /* .members */ +}, +/* ReadValueId */ +{ + UA_TYPENAME("ReadValueId") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {626LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {628LU}}, /* .binaryEncodingId */ + sizeof(UA_ReadValueId), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + ReadValueId_members /* .members */ +}, +/* ReadRequest */ +{ + UA_TYPENAME("ReadRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {629LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {631LU}}, /* .binaryEncodingId */ + sizeof(UA_ReadRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + ReadRequest_members /* .members */ +}, +/* ReadResponse */ +{ + UA_TYPENAME("ReadResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {632LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {634LU}}, /* .binaryEncodingId */ + sizeof(UA_ReadResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + ReadResponse_members /* .members */ +}, +/* WriteValue */ +{ + UA_TYPENAME("WriteValue") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {668LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {670LU}}, /* .binaryEncodingId */ + sizeof(UA_WriteValue), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + WriteValue_members /* .members */ +}, +/* WriteRequest */ +{ + UA_TYPENAME("WriteRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {671LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {673LU}}, /* .binaryEncodingId */ + sizeof(UA_WriteRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + WriteRequest_members /* .members */ +}, +/* WriteResponse */ +{ + UA_TYPENAME("WriteResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {674LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {676LU}}, /* .binaryEncodingId */ + sizeof(UA_WriteResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + WriteResponse_members /* .members */ +}, +/* CallMethodRequest */ +{ + UA_TYPENAME("CallMethodRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {704LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {706LU}}, /* .binaryEncodingId */ + sizeof(UA_CallMethodRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + CallMethodRequest_members /* .members */ +}, +/* CallMethodResult */ +{ + UA_TYPENAME("CallMethodResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {707LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {709LU}}, /* .binaryEncodingId */ + sizeof(UA_CallMethodResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + CallMethodResult_members /* .members */ +}, +/* CallRequest */ +{ + UA_TYPENAME("CallRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {710LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {712LU}}, /* .binaryEncodingId */ + sizeof(UA_CallRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + CallRequest_members /* .members */ +}, +/* CallResponse */ +{ + UA_TYPENAME("CallResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {713LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {715LU}}, /* .binaryEncodingId */ + sizeof(UA_CallResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + CallResponse_members /* .members */ +}, +/* MonitoringMode */ +{ + UA_TYPENAME("MonitoringMode") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {716LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_MonitoringMode), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + MonitoringMode_members /* .members */ +}, +/* DataChangeTrigger */ +{ + UA_TYPENAME("DataChangeTrigger") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {717LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_DataChangeTrigger), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + DataChangeTrigger_members /* .members */ +}, +/* DeadbandType */ +{ + UA_TYPENAME("DeadbandType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {718LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_DeadbandType), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + DeadbandType_members /* .members */ +}, +/* DataChangeFilter */ +{ + UA_TYPENAME("DataChangeFilter") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {722LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {724LU}}, /* .binaryEncodingId */ + sizeof(UA_DataChangeFilter), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + DataChangeFilter_members /* .members */ +}, +/* EventFilter */ +{ + UA_TYPENAME("EventFilter") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {725LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {727LU}}, /* .binaryEncodingId */ + sizeof(UA_EventFilter), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + EventFilter_members /* .members */ +}, +/* AggregateConfiguration */ +{ + UA_TYPENAME("AggregateConfiguration") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {948LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {950LU}}, /* .binaryEncodingId */ + sizeof(UA_AggregateConfiguration), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + AggregateConfiguration_members /* .members */ +}, +/* AggregateFilter */ +{ + UA_TYPENAME("AggregateFilter") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {728LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {730LU}}, /* .binaryEncodingId */ + sizeof(UA_AggregateFilter), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + AggregateFilter_members /* .members */ +}, +/* EventFilterResult */ +{ + UA_TYPENAME("EventFilterResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {734LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {736LU}}, /* .binaryEncodingId */ + sizeof(UA_EventFilterResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + EventFilterResult_members /* .members */ +}, +/* MonitoringParameters */ +{ + UA_TYPENAME("MonitoringParameters") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {740LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {742LU}}, /* .binaryEncodingId */ + sizeof(UA_MonitoringParameters), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + MonitoringParameters_members /* .members */ +}, +/* MonitoredItemCreateRequest */ +{ + UA_TYPENAME("MonitoredItemCreateRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {743LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {745LU}}, /* .binaryEncodingId */ + sizeof(UA_MonitoredItemCreateRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + MonitoredItemCreateRequest_members /* .members */ +}, +/* MonitoredItemCreateResult */ +{ + UA_TYPENAME("MonitoredItemCreateResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {746LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {748LU}}, /* .binaryEncodingId */ + sizeof(UA_MonitoredItemCreateResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + MonitoredItemCreateResult_members /* .members */ +}, +/* CreateMonitoredItemsRequest */ +{ + UA_TYPENAME("CreateMonitoredItemsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {749LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {751LU}}, /* .binaryEncodingId */ + sizeof(UA_CreateMonitoredItemsRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + CreateMonitoredItemsRequest_members /* .members */ +}, +/* CreateMonitoredItemsResponse */ +{ + UA_TYPENAME("CreateMonitoredItemsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {752LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {754LU}}, /* .binaryEncodingId */ + sizeof(UA_CreateMonitoredItemsResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + CreateMonitoredItemsResponse_members /* .members */ +}, +/* MonitoredItemModifyRequest */ +{ + UA_TYPENAME("MonitoredItemModifyRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {755LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {757LU}}, /* .binaryEncodingId */ + sizeof(UA_MonitoredItemModifyRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + MonitoredItemModifyRequest_members /* .members */ +}, +/* MonitoredItemModifyResult */ +{ + UA_TYPENAME("MonitoredItemModifyResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {758LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {760LU}}, /* .binaryEncodingId */ + sizeof(UA_MonitoredItemModifyResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + MonitoredItemModifyResult_members /* .members */ +}, +/* ModifyMonitoredItemsRequest */ +{ + UA_TYPENAME("ModifyMonitoredItemsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {761LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {763LU}}, /* .binaryEncodingId */ + sizeof(UA_ModifyMonitoredItemsRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + ModifyMonitoredItemsRequest_members /* .members */ +}, +/* ModifyMonitoredItemsResponse */ +{ + UA_TYPENAME("ModifyMonitoredItemsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {764LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {766LU}}, /* .binaryEncodingId */ + sizeof(UA_ModifyMonitoredItemsResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + ModifyMonitoredItemsResponse_members /* .members */ +}, +/* SetMonitoringModeRequest */ +{ + UA_TYPENAME("SetMonitoringModeRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {767LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {769LU}}, /* .binaryEncodingId */ + sizeof(UA_SetMonitoringModeRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + SetMonitoringModeRequest_members /* .members */ +}, +/* SetMonitoringModeResponse */ +{ + UA_TYPENAME("SetMonitoringModeResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {770LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {772LU}}, /* .binaryEncodingId */ + sizeof(UA_SetMonitoringModeResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + SetMonitoringModeResponse_members /* .members */ +}, +/* SetTriggeringRequest */ +{ + UA_TYPENAME("SetTriggeringRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {773LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {775LU}}, /* .binaryEncodingId */ + sizeof(UA_SetTriggeringRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + SetTriggeringRequest_members /* .members */ +}, +/* SetTriggeringResponse */ +{ + UA_TYPENAME("SetTriggeringResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {776LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {778LU}}, /* .binaryEncodingId */ + sizeof(UA_SetTriggeringResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + SetTriggeringResponse_members /* .members */ +}, +/* DeleteMonitoredItemsRequest */ +{ + UA_TYPENAME("DeleteMonitoredItemsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {779LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {781LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteMonitoredItemsRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + DeleteMonitoredItemsRequest_members /* .members */ +}, +/* DeleteMonitoredItemsResponse */ +{ + UA_TYPENAME("DeleteMonitoredItemsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {782LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {784LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteMonitoredItemsResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + DeleteMonitoredItemsResponse_members /* .members */ +}, +/* CreateSubscriptionRequest */ +{ + UA_TYPENAME("CreateSubscriptionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {785LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {787LU}}, /* .binaryEncodingId */ + sizeof(UA_CreateSubscriptionRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + CreateSubscriptionRequest_members /* .members */ +}, +/* CreateSubscriptionResponse */ +{ + UA_TYPENAME("CreateSubscriptionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {788LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {790LU}}, /* .binaryEncodingId */ + sizeof(UA_CreateSubscriptionResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + CreateSubscriptionResponse_members /* .members */ +}, +/* ModifySubscriptionRequest */ +{ + UA_TYPENAME("ModifySubscriptionRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {791LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {793LU}}, /* .binaryEncodingId */ + sizeof(UA_ModifySubscriptionRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + ModifySubscriptionRequest_members /* .members */ +}, +/* ModifySubscriptionResponse */ +{ + UA_TYPENAME("ModifySubscriptionResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {794LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {796LU}}, /* .binaryEncodingId */ + sizeof(UA_ModifySubscriptionResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + ModifySubscriptionResponse_members /* .members */ +}, +/* SetPublishingModeRequest */ +{ + UA_TYPENAME("SetPublishingModeRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {797LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {799LU}}, /* .binaryEncodingId */ + sizeof(UA_SetPublishingModeRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + SetPublishingModeRequest_members /* .members */ +}, +/* SetPublishingModeResponse */ +{ + UA_TYPENAME("SetPublishingModeResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {800LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {802LU}}, /* .binaryEncodingId */ + sizeof(UA_SetPublishingModeResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + SetPublishingModeResponse_members /* .members */ +}, +/* NotificationMessage */ +{ + UA_TYPENAME("NotificationMessage") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {803LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {805LU}}, /* .binaryEncodingId */ + sizeof(UA_NotificationMessage), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + NotificationMessage_members /* .members */ +}, +/* MonitoredItemNotification */ +{ + UA_TYPENAME("MonitoredItemNotification") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {806LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {808LU}}, /* .binaryEncodingId */ + sizeof(UA_MonitoredItemNotification), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + MonitoredItemNotification_members /* .members */ +}, +/* EventFieldList */ +{ + UA_TYPENAME("EventFieldList") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {917LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {919LU}}, /* .binaryEncodingId */ + sizeof(UA_EventFieldList), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + EventFieldList_members /* .members */ +}, +/* StatusChangeNotification */ +{ + UA_TYPENAME("StatusChangeNotification") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {818LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {820LU}}, /* .binaryEncodingId */ + sizeof(UA_StatusChangeNotification), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + StatusChangeNotification_members /* .members */ +}, +/* SubscriptionAcknowledgement */ +{ + UA_TYPENAME("SubscriptionAcknowledgement") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {821LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {823LU}}, /* .binaryEncodingId */ + sizeof(UA_SubscriptionAcknowledgement), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + SubscriptionAcknowledgement_members /* .members */ +}, +/* PublishRequest */ +{ + UA_TYPENAME("PublishRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {824LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {826LU}}, /* .binaryEncodingId */ + sizeof(UA_PublishRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + PublishRequest_members /* .members */ +}, +/* PublishResponse */ +{ + UA_TYPENAME("PublishResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {827LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {829LU}}, /* .binaryEncodingId */ + sizeof(UA_PublishResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 7, /* .membersSize */ + PublishResponse_members /* .members */ +}, +/* RepublishRequest */ +{ + UA_TYPENAME("RepublishRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {830LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {832LU}}, /* .binaryEncodingId */ + sizeof(UA_RepublishRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + RepublishRequest_members /* .members */ +}, +/* RepublishResponse */ +{ + UA_TYPENAME("RepublishResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {833LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {835LU}}, /* .binaryEncodingId */ + sizeof(UA_RepublishResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + RepublishResponse_members /* .members */ +}, +/* TransferResult */ +{ + UA_TYPENAME("TransferResult") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {836LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {838LU}}, /* .binaryEncodingId */ + sizeof(UA_TransferResult), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + TransferResult_members /* .members */ +}, +/* TransferSubscriptionsRequest */ +{ + UA_TYPENAME("TransferSubscriptionsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {839LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {841LU}}, /* .binaryEncodingId */ + sizeof(UA_TransferSubscriptionsRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + TransferSubscriptionsRequest_members /* .members */ +}, +/* TransferSubscriptionsResponse */ +{ + UA_TYPENAME("TransferSubscriptionsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {842LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {844LU}}, /* .binaryEncodingId */ + sizeof(UA_TransferSubscriptionsResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + TransferSubscriptionsResponse_members /* .members */ +}, +/* DeleteSubscriptionsRequest */ +{ + UA_TYPENAME("DeleteSubscriptionsRequest") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {845LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {847LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteSubscriptionsRequest), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + DeleteSubscriptionsRequest_members /* .members */ +}, +/* DeleteSubscriptionsResponse */ +{ + UA_TYPENAME("DeleteSubscriptionsResponse") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {848LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {850LU}}, /* .binaryEncodingId */ + sizeof(UA_DeleteSubscriptionsResponse), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + DeleteSubscriptionsResponse_members /* .members */ +}, +/* BuildInfo */ +{ + UA_TYPENAME("BuildInfo") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {338LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {340LU}}, /* .binaryEncodingId */ + sizeof(UA_BuildInfo), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + BuildInfo_members /* .members */ +}, +/* RedundancySupport */ +{ + UA_TYPENAME("RedundancySupport") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {851LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_RedundancySupport), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + RedundancySupport_members /* .members */ +}, +/* ServerState */ +{ + UA_TYPENAME("ServerState") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {852LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_ServerState), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + ServerState_members /* .members */ +}, +/* ServerDiagnosticsSummaryDataType */ +{ + UA_TYPENAME("ServerDiagnosticsSummaryDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {859LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {861LU}}, /* .binaryEncodingId */ + sizeof(UA_ServerDiagnosticsSummaryDataType), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 12, /* .membersSize */ + ServerDiagnosticsSummaryDataType_members /* .members */ +}, +/* ServerStatusDataType */ +{ + UA_TYPENAME("ServerStatusDataType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {862LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {864LU}}, /* .binaryEncodingId */ + sizeof(UA_ServerStatusDataType), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + ServerStatusDataType_members /* .members */ +}, +/* Range */ +{ + UA_TYPENAME("Range") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {884LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {886LU}}, /* .binaryEncodingId */ + sizeof(UA_Range), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + Range_members /* .members */ +}, +/* EUInformation */ +{ + UA_TYPENAME("EUInformation") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {887LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {889LU}}, /* .binaryEncodingId */ + sizeof(UA_EUInformation), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 4, /* .membersSize */ + EUInformation_members /* .members */ +}, +/* AxisScaleEnumeration */ +{ + UA_TYPENAME("AxisScaleEnumeration") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12077LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_AxisScaleEnumeration), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + AxisScaleEnumeration_members /* .members */ +}, +/* ComplexNumberType */ +{ + UA_TYPENAME("ComplexNumberType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12171LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12181LU}}, /* .binaryEncodingId */ + sizeof(UA_ComplexNumberType), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + ComplexNumberType_members /* .members */ +}, +/* DoubleComplexNumberType */ +{ + UA_TYPENAME("DoubleComplexNumberType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12172LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12182LU}}, /* .binaryEncodingId */ + sizeof(UA_DoubleComplexNumberType), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + DoubleComplexNumberType_members /* .members */ +}, +/* AxisInformation */ +{ + UA_TYPENAME("AxisInformation") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12079LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12089LU}}, /* .binaryEncodingId */ + sizeof(UA_AxisInformation), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + AxisInformation_members /* .members */ +}, +/* XVType */ +{ + UA_TYPENAME("XVType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {12080LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {12090LU}}, /* .binaryEncodingId */ + sizeof(UA_XVType), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + XVType_members /* .members */ +}, +/* EnumDefinition */ +{ + UA_TYPENAME("EnumDefinition") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {100LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {123LU}}, /* .binaryEncodingId */ + sizeof(UA_EnumDefinition), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + EnumDefinition_members /* .members */ +}, +/* DataChangeNotification */ +{ + UA_TYPENAME("DataChangeNotification") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {809LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {811LU}}, /* .binaryEncodingId */ + sizeof(UA_DataChangeNotification), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + DataChangeNotification_members /* .members */ +}, +/* EventNotificationList */ +{ + UA_TYPENAME("EventNotificationList") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {914LU}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {916LU}}, /* .binaryEncodingId */ + sizeof(UA_EventNotificationList), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 1, /* .membersSize */ + EventNotificationList_members /* .members */ +}, +}; + + +/**** amalgamated original file "/build_freeRTOS/src_generated/open62541/transport_generated.c" ****/ + +/********************************** + * Autogenerated -- do not modify * + **********************************/ + + +/* MessageType */ +#define MessageType_members NULL + +/* ChunkType */ +#define ChunkType_members NULL + +/* TcpMessageHeader */ +static UA_DataTypeMember TcpMessageHeader_members[2] = { +{ + UA_TYPENAME("MessageTypeAndChunkType") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MessageSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TcpMessageHeader, messageSize) - offsetof(UA_TcpMessageHeader, messageTypeAndChunkType) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* TcpHelloMessage */ +static UA_DataTypeMember TcpHelloMessage_members[6] = { +{ + UA_TYPENAME("ProtocolVersion") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReceiveBufferSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TcpHelloMessage, receiveBufferSize) - offsetof(UA_TcpHelloMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SendBufferSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TcpHelloMessage, sendBufferSize) - offsetof(UA_TcpHelloMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxMessageSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TcpHelloMessage, maxMessageSize) - offsetof(UA_TcpHelloMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxChunkCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TcpHelloMessage, maxChunkCount) - offsetof(UA_TcpHelloMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("EndpointUrl") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_TcpHelloMessage, endpointUrl) - offsetof(UA_TcpHelloMessage, maxChunkCount) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* TcpAcknowledgeMessage */ +static UA_DataTypeMember TcpAcknowledgeMessage_members[5] = { +{ + UA_TYPENAME("ProtocolVersion") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReceiveBufferSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - offsetof(UA_TcpAcknowledgeMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SendBufferSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxMessageSize") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("MaxChunkCount") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_TcpAcknowledgeMessage, maxChunkCount) - offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* TcpErrorMessage */ +static UA_DataTypeMember TcpErrorMessage_members[2] = { +{ + UA_TYPENAME("Error") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("Reason") /* .memberName */ + &UA_TYPES[UA_TYPES_STRING], /* .memberType */ + offsetof(UA_TcpErrorMessage, reason) - offsetof(UA_TcpErrorMessage, error) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* AsymmetricAlgorithmSecurityHeader */ +static UA_DataTypeMember AsymmetricAlgorithmSecurityHeader_members[3] = { +{ + UA_TYPENAME("SecurityPolicyUri") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("SenderCertificate") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, securityPolicyUri) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("ReceiverCertificateThumbprint") /* .memberName */ + &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */ + offsetof(UA_AsymmetricAlgorithmSecurityHeader, receiverCertificateThumbprint) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - sizeof(UA_ByteString), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; + +/* SequenceHeader */ +static UA_DataTypeMember SequenceHeader_members[2] = { +{ + UA_TYPENAME("SequenceNumber") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + 0, /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +}, +{ + UA_TYPENAME("RequestId") /* .memberName */ + &UA_TYPES[UA_TYPES_UINT32], /* .memberType */ + offsetof(UA_SequenceHeader, requestId) - offsetof(UA_SequenceHeader, sequenceNumber) - sizeof(UA_UInt32), /* .padding */ + false, /* .isArray */ + false /* .isOptional */ +},}; +const UA_DataType UA_TRANSPORT[UA_TRANSPORT_COUNT] = { +/* MessageType */ +{ + UA_TYPENAME("MessageType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_MessageType), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + MessageType_members /* .members */ +}, +/* ChunkType */ +{ + UA_TYPENAME("ChunkType") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_ChunkType), /* .memSize */ + UA_DATATYPEKIND_ENUM, /* .typeKind */ + true, /* .pointerFree */ + UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */ + 0, /* .membersSize */ + ChunkType_members /* .members */ +}, +/* TcpMessageHeader */ +{ + UA_TYPENAME("TcpMessageHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_TcpMessageHeader), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + TcpMessageHeader_members /* .members */ +}, +/* TcpHelloMessage */ +{ + UA_TYPENAME("TcpHelloMessage") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_TcpHelloMessage), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 6, /* .membersSize */ + TcpHelloMessage_members /* .members */ +}, +/* TcpAcknowledgeMessage */ +{ + UA_TYPENAME("TcpAcknowledgeMessage") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_TcpAcknowledgeMessage), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 5, /* .membersSize */ + TcpAcknowledgeMessage_members /* .members */ +}, +/* TcpErrorMessage */ +{ + UA_TYPENAME("TcpErrorMessage") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_TcpErrorMessage), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + TcpErrorMessage_members /* .members */ +}, +/* AsymmetricAlgorithmSecurityHeader */ +{ + UA_TYPENAME("AsymmetricAlgorithmSecurityHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_AsymmetricAlgorithmSecurityHeader), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + false, /* .pointerFree */ + false, /* .overlayable */ + 3, /* .membersSize */ + AsymmetricAlgorithmSecurityHeader_members /* .members */ +}, +/* SequenceHeader */ +{ + UA_TYPENAME("SequenceHeader") /* .typeName */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */ + {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */ + sizeof(UA_SequenceHeader), /* .memSize */ + UA_DATATYPEKIND_STRUCTURE, /* .typeKind */ + true, /* .pointerFree */ + false, /* .overlayable */ + 2, /* .membersSize */ + SequenceHeader_members /* .members */ +}, +}; + + +/**** amalgamated original file "/build_freeRTOS/src_generated/open62541/statuscodes.c" ****/ + +/********************************** + * Autogenerated -- do not modify * + **********************************/ + + +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 = 252; +static const UA_StatusCodeName statusCodeDescriptions[252] = { + {UA_STATUSCODE_GOOD, "Good"}, + {UA_STATUSCODE_GOOD, "Good"}, + {UA_STATUSCODE_UNCERTAIN, "Uncertain"}, + {UA_STATUSCODE_BAD, "Bad"}, + {UA_STATUSCODE_BADUNEXPECTEDERROR, "BadUnexpectedError"}, + {UA_STATUSCODE_BADINTERNALERROR, "BadInternalError"}, + {UA_STATUSCODE_BADOUTOFMEMORY, "BadOutOfMemory"}, + {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_BADCERTIFICATEPOLICYCHECKFAILED, "BadCertificatePolicyCheckFailed"}, + {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_BADLICENSEEXPIRED, "BadLicenseExpired"}, + {UA_STATUSCODE_BADLICENSELIMITSEXCEEDED, "BadLicenseLimitsExceeded"}, + {UA_STATUSCODE_BADLICENSENOTAVAILABLE, "BadLicenseNotAvailable"}, + {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_BADNUMERICOVERFLOW, "BadNumericOverflow"}, + {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_BADNOTEXECUTABLE, "BadNotExecutable"}, + {UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS, "BadTooManySubscriptions"}, + {UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS, "BadTooManyPublishRequests"}, + {UA_STATUSCODE_BADNOSUBSCRIPTION, "BadNoSubscription"}, + {UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN, "BadSequenceNumberUnknown"}, + {UA_STATUSCODE_GOODRETRANSMISSIONQUEUENOTSUPPORTED, "GoodRetransmissionQueueNotSupported"}, + {UA_STATUSCODE_BADMESSAGENOTAVAILABLE, "BadMessageNotAvailable"}, + {UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE, "BadInsufficientClientProfile"}, + {UA_STATUSCODE_BADSTATENOTACTIVE, "BadStateNotActive"}, + {UA_STATUSCODE_BADALREADYEXISTS, "BadAlreadyExists"}, + {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_BADREQUESTNOTCOMPLETE, "BadRequestNotComplete"}, + {UA_STATUSCODE_BADTICKETREQUIRED, "BadTicketRequired"}, + {UA_STATUSCODE_BADTICKETINVALID, "BadTicketInvalid"}, + {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_GOODEDITED_DEPENDENTVALUECHANGED, "GoodEdited_DependentValueChanged"}, + {UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED, "GoodEdited_DominantValueChanged"}, + {UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "GoodEdited_DominantValueChanged_DependentValueChanged"}, + {UA_STATUSCODE_BADEDITED_OUTOFRANGE, "BadEdited_OutOfRange"}, + {UA_STATUSCODE_BADINITIALVALUE_OUTOFRANGE, "BadInitialValue_OutOfRange"}, + {UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED, "BadOutOfRange_DominantValueChanged"}, + {UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED, "BadEdited_OutOfRange_DominantValueChanged"}, + {UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "BadOutOfRange_DominantValueChanged_DependentValueChanged"}, + {UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "BadEdited_OutOfRange_DominantValueChanged_DependentValueChanged"}, + {UA_STATUSCODE_GOODCOMMUNICATIONEVENT, "GoodCommunicationEvent"}, + {UA_STATUSCODE_GOODSHUTDOWNEVENT, "GoodShutdownEvent"}, + {UA_STATUSCODE_GOODCALLAGAIN, "GoodCallAgain"}, + {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 "/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) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2014 (c) Florian Palm + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + + +size_t +UA_readNumberWithBase(const UA_Byte *buf, size_t buflen, UA_UInt32 *number, UA_Byte base) { + 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' && c <= '0' + (base-1)) + n = (n * base) + c - '0'; + else if(base > 9 && c >= 'a' && c <= 'z' && c <= 'a' + (base-11)) + n = (n * base) + c-'a' + 10; + else if(base > 9 && c >= 'A' && c <= 'Z' && c <= 'A' + (base-11)) + n = (n * base) + c-'A' + 10; + else + break; + ++progress; + } + *number = n; + return progress; +} + +size_t +UA_readNumber(const UA_Byte *buf, size_t buflen, UA_UInt32 *number) { + return UA_readNumberWithBase(buf, buflen, number, 10); +} + +UA_StatusCode +UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname, + u16 *outPort, UA_String *outPath) { + UA_Boolean ipv6 = false; + + /* Url must begin with "opc.tcp://" or opc.udp:// (if pubsub enabled) */ + if(endpointUrl->length < 11) { + return UA_STATUSCODE_BADTCPENDPOINTURLINVALID; + } + if (strncmp((char*)endpointUrl->data, "opc.tcp://", 10) != 0) { +#ifdef UA_ENABLE_PUBSUB + if (strncmp((char*)endpointUrl->data, "opc.udp://", 10) != 0 && + strncmp((char*)endpointUrl->data, "opc.mqtt://", 11) != 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++; + ipv6 = true; + } 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 */ + if(ipv6) { + /* Skip the ipv6 '[]' container for getaddrinfo() later */ + outHostname->data = &endpointUrl->data[11]; + outHostname->length = curr - 12; + } else { + outHostname->data = &endpointUrl->data[10]; + outHostname->length = curr - 10; + } + + /* Empty string? */ + if(outHostname->length == 0) + outHostname->data = NULL; + + if(curr == endpointUrl->length) + return UA_STATUSCODE_GOOD; + + /* 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--; + + /* Empty string? */ + if(outPath->length == 0) + outPath->data = NULL; + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_parseEndpointUrlEthernet(const UA_String *endpointUrl, UA_String *target, + UA_UInt16 *vid, UA_Byte *pcp) { + /* Url must begin with "opc.eth://" */ + if(endpointUrl->length < 11) { + return UA_STATUSCODE_BADINTERNALERROR; + } + if(strncmp((char*) endpointUrl->data, "opc.eth://", 10) != 0) { + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* Where does the host address end? */ + size_t curr = 10; + for(; curr < endpointUrl->length; ++curr) { + if(endpointUrl->data[curr] == ':') { + break; + } + } + + /* set host address */ + target->data = &endpointUrl->data[10]; + target->length = curr - 10; + if(curr == endpointUrl->length) { + return UA_STATUSCODE_GOOD; + } + + /* Set VLAN */ + u32 value = 0; + curr++; /* skip ':' */ + size_t progress = UA_readNumber(&endpointUrl->data[curr], + endpointUrl->length - curr, &value); + if(progress == 0 || value > 4096) { + return UA_STATUSCODE_BADINTERNALERROR; + } + curr += progress; + if(curr == endpointUrl->length || endpointUrl->data[curr] == '.') { + *vid = (UA_UInt16) value; + } + if(curr == endpointUrl->length) { + return UA_STATUSCODE_GOOD; + } + + /* Set priority */ + if(endpointUrl->data[curr] != '.') { + return UA_STATUSCODE_BADINTERNALERROR; + } + curr++; /* skip '.' */ + progress = UA_readNumber(&endpointUrl->data[curr], + endpointUrl->length - curr, &value); + if(progress == 0 || value > 7) { + return UA_STATUSCODE_BADINTERNALERROR; + } + curr += progress; + if(curr != endpointUrl->length) { + return UA_STATUSCODE_BADINTERNALERROR; + } + *pcp = (UA_Byte) value; + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_ByteString_toBase64(const UA_ByteString *byteString, + UA_String *str) { + UA_String_init(str); + if(!byteString || !byteString->data) + return UA_STATUSCODE_GOOD; + + str->data = (UA_Byte*) + UA_base64(byteString->data, byteString->length, &str->length); + if(!str->data) + return UA_STATUSCODE_BADOUTOFMEMORY; + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode UA_EXPORT +UA_ByteString_fromBase64(UA_ByteString *bs, + const UA_String *input) { + UA_ByteString_init(bs); + if(input->length == 0) + return UA_STATUSCODE_GOOD; + bs->data = UA_unbase64((const unsigned char*)input->data, + input->length, &bs->length); + /* TODO: Differentiate between encoding and memory errors */ + if(!bs->data) + return UA_STATUSCODE_BADINTERNALERROR; + return UA_STATUSCODE_GOOD; +} + +/* Key Value Map */ + +UA_StatusCode +UA_KeyValueMap_setQualified(UA_KeyValuePair **map, size_t *mapSize, + const UA_QualifiedName *key, + const UA_Variant *value) { + /* Parameter exists already */ + const UA_Variant *v = UA_KeyValueMap_getQualified(*map, *mapSize, key); + if(v) { + UA_Variant copyV; + UA_StatusCode res = UA_Variant_copy(v, ©V); + if(res != UA_STATUSCODE_GOOD) + return res; + UA_Variant *target = (UA_Variant*)(uintptr_t)v; + UA_Variant_clear(target); + *target = copyV; + return UA_STATUSCODE_GOOD; + } + + /* Append to the array */ + UA_KeyValuePair pair; + pair.key = *key; + pair.value = *value; + return UA_Array_appendCopy((void**)map, mapSize, &pair, + &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); +} + +UA_StatusCode +UA_KeyValueMap_set(UA_KeyValuePair **map, size_t *mapSize, + const char *key, const UA_Variant *value) { + UA_QualifiedName qnKey; + qnKey.namespaceIndex = 0; + qnKey.name = UA_STRING((char*)(uintptr_t)key); + return UA_KeyValueMap_setQualified(map, mapSize, &qnKey, value); +} + +const UA_Variant * +UA_KeyValueMap_getQualified(UA_KeyValuePair *map, size_t mapSize, + const UA_QualifiedName *key) { + for(size_t i = 0; i < mapSize; i++) { + if(map[i].key.namespaceIndex == key->namespaceIndex && + UA_String_equal(&map[i].key.name, &key->name)) + return &map[i].value; + + } + return NULL; +} + +const UA_Variant * +UA_KeyValueMap_get(UA_KeyValuePair *map, size_t mapSize, + const char *key) { + UA_QualifiedName qnKey; + qnKey.namespaceIndex = 0; + qnKey.name = UA_STRING((char*)(uintptr_t)key); + return UA_KeyValueMap_getQualified(map, mapSize, &qnKey); +} + +/* Returns NULL if the parameter is not defined or not of the right datatype */ +const UA_Variant * +UA_KeyValueMap_getScalar(UA_KeyValuePair *map, size_t mapSize, + const char *key, const UA_DataType *type) { + const UA_Variant *v = UA_KeyValueMap_get(map, mapSize, key); + if(!v || !UA_Variant_hasScalarType(v, type)) + return NULL; + return v; +} + +const UA_Variant * +UA_KeyValueMap_getArray(UA_KeyValuePair *map, size_t mapSize, + const char *key, const UA_DataType *type) { + const UA_Variant *v = UA_KeyValueMap_get(map, mapSize, key); + if(!v || !UA_Variant_hasArrayType(v, type)) + return NULL; + return v; +} + +void +UA_KeyValueMap_deleteQualified(UA_KeyValuePair **map, size_t *mapSize, + const UA_QualifiedName *key) { + UA_KeyValuePair *m = *map; + size_t s = *mapSize; + for(size_t i = 0; i < s; i++) { + if(m[i].key.namespaceIndex != key->namespaceIndex || + !UA_String_equal(&m[i].key.name, &key->name)) + continue; + + /* Clean the pair */ + UA_KeyValuePair_clear(&m[i]); + + /* Move the last pair to fill the empty slot */ + if(s > 1 && i < s - 1) { + m[i] = m[s-1]; + UA_KeyValuePair_init(&m[s-1]); + } + + UA_StatusCode res = UA_Array_resize((void**)map, mapSize, *mapSize-1, + &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); + (void)res; + *mapSize = s - 1; /* In case resize fails, keep the longer original + * array around. Resize never fails when reducing + * the size to zero. Reduce the size integer in + * any case. */ + return; + } +} + +void +UA_KeyValueMap_delete(UA_KeyValuePair **map, size_t *mapSize, + const char *key) { + UA_QualifiedName qnKey; + qnKey.namespaceIndex = 0; + qnKey.name = UA_STRING((char*)(uintptr_t)key); + UA_KeyValueMap_deleteQualified(map, mapSize, &qnKey); +} + +/**** amalgamated original file "/src/ua_timer.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2017, 2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + */ + + +/* There may be several entries with the same nextTime in the tree. We give them + * an absolute order by considering the memory address to break ties. Because of + * this, the nextTime property cannot be used to lookup specific entries. */ +static enum aa_cmp +cmpDateTime(const UA_DateTime *a, const UA_DateTime *b) { + if(*a < *b) + return AA_CMP_LESS; + if(*a > *b) + return AA_CMP_MORE; + if(a == b) + return AA_CMP_EQ; + if(a < b) + return AA_CMP_LESS; + return AA_CMP_MORE; +} + +/* The identifiers of entries are unique */ +static enum aa_cmp +cmpId(const UA_UInt64 *a, const UA_UInt64 *b) { + if(*a < *b) + return AA_CMP_LESS; + if(*a == *b) + return AA_CMP_EQ; + return AA_CMP_MORE; +} + +static UA_DateTime +calculateNextTime(UA_DateTime currentTime, UA_DateTime baseTime, + UA_DateTime interval) { + /* Take the difference between current and base time */ + UA_DateTime diffCurrentTimeBaseTime = currentTime - baseTime; + + /* Take modulo of the diff time with the interval. This is the duration we + * are already "into" the current interval. Subtract it from (current + + * interval) to get the next execution time. */ + UA_DateTime cycleDelay = diffCurrentTimeBaseTime % interval; + + /* Handle the special case where the baseTime is in the future */ + if(UA_UNLIKELY(cycleDelay < 0)) + cycleDelay += interval; + + return currentTime + interval - cycleDelay; +} + +void +UA_Timer_init(UA_Timer *t) { + memset(t, 0, sizeof(UA_Timer)); + aa_init(&t->root, + (enum aa_cmp (*)(const void*, const void*))cmpDateTime, + offsetof(UA_TimerEntry, treeEntry), + offsetof(UA_TimerEntry, nextTime)); + aa_init(&t->idRoot, + (enum aa_cmp (*)(const void*, const void*))cmpId, + offsetof(UA_TimerEntry, idTreeEntry), + offsetof(UA_TimerEntry, id)); + UA_LOCK_INIT(&t->timerMutex); +} + +void +UA_Timer_addTimerEntry(UA_Timer *t, UA_TimerEntry *te, UA_UInt64 *callbackId) { + UA_LOCK(&t->timerMutex); + te->id = ++t->idCounter; + if(callbackId) + *callbackId = te->id; + aa_insert(&t->root, te); + aa_insert(&t->idRoot, te); + UA_UNLOCK(&t->timerMutex); +} + +static UA_StatusCode +addCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application, + void *data, UA_DateTime nextTime, UA_UInt64 interval, + UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId) { + /* A callback method needs to be present */ + if(!callback) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Allocate the repeated callback structure */ + UA_TimerEntry *te = (UA_TimerEntry*)UA_malloc(sizeof(UA_TimerEntry)); + if(!te) + return UA_STATUSCODE_BADOUTOFMEMORY; + + /* Set the repeated callback */ + te->interval = (UA_UInt64)interval; + te->id = ++t->idCounter; + te->callback = callback; + te->application = application; + te->data = data; + te->nextTime = nextTime; + te->timerPolicy = timerPolicy; + + /* Set the output identifier */ + if(callbackId) + *callbackId = te->id; + + aa_insert(&t->root, te); + aa_insert(&t->idRoot, te); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Timer_addTimedCallback(UA_Timer *t, UA_ApplicationCallback callback, + void *application, void *data, UA_DateTime date, + UA_UInt64 *callbackId) { + UA_LOCK(&t->timerMutex); + UA_StatusCode res = addCallback(t, callback, application, data, date, + 0, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, + callbackId); + UA_UNLOCK(&t->timerMutex); + return res; +} + +/* Adding repeated callbacks: Add an entry with the "nextTime" timestamp in the + * 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_ApplicationCallback callback, + void *application, void *data, UA_Double interval_ms, + UA_DateTime *baseTime, UA_TimerPolicy timerPolicy, + UA_UInt64 *callbackId) { + /* The interval needs to be positive */ + if(interval_ms <= 0.0) + return UA_STATUSCODE_BADINTERNALERROR; + UA_UInt64 interval = (UA_UInt64)(interval_ms * UA_DATETIME_MSEC); + if(interval == 0) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Compute the first time for execution */ + UA_DateTime currentTime = UA_DateTime_nowMonotonic(); + UA_DateTime nextTime; + if(baseTime == NULL) { + /* Use "now" as the basetime */ + nextTime = currentTime + (UA_DateTime)interval; + } else { + nextTime = calculateNextTime(currentTime, *baseTime, (UA_DateTime)interval); + } + + UA_LOCK(&t->timerMutex); + UA_StatusCode res = addCallback(t, callback, application, data, nextTime, + interval, timerPolicy, callbackId); + UA_UNLOCK(&t->timerMutex); + return res; +} + +UA_StatusCode +UA_Timer_changeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId, + UA_Double interval_ms, UA_DateTime *baseTime, + UA_TimerPolicy timerPolicy) { + /* The interval needs to be positive */ + if(interval_ms <= 0.0) + return UA_STATUSCODE_BADINTERNALERROR; + UA_UInt64 interval = (UA_UInt64)(interval_ms * UA_DATETIME_MSEC); + if(interval == 0) + return UA_STATUSCODE_BADINTERNALERROR; + + UA_LOCK(&t->timerMutex); + + /* Remove from the sorted tree */ + UA_TimerEntry *te = (UA_TimerEntry*)aa_find(&t->idRoot, &callbackId); + if(!te) { + UA_UNLOCK(&t->timerMutex); + return UA_STATUSCODE_BADNOTFOUND; + } + aa_remove(&t->root, te); + + /* Compute the next time for execution. The logic is identical to the + * creation of a new repeated callback. */ + UA_DateTime currentTime = UA_DateTime_nowMonotonic(); + if(baseTime == NULL) { + /* Use "now" as the basetime */ + te->nextTime = currentTime + (UA_DateTime)interval; + } else { + te->nextTime = calculateNextTime(currentTime, *baseTime, (UA_DateTime)interval); + } + + /* Update the remaining parameters and re-insert */ + te->interval = interval; + te->timerPolicy = timerPolicy; + aa_insert(&t->root, te); + + UA_UNLOCK(&t->timerMutex); + return UA_STATUSCODE_GOOD; +} + +void +UA_Timer_removeCallback(UA_Timer *t, UA_UInt64 callbackId) { + UA_LOCK(&t->timerMutex); + UA_TimerEntry *te = (UA_TimerEntry*)aa_find(&t->idRoot, &callbackId); + if(UA_LIKELY(te != NULL)) { + aa_remove(&t->root, te); + aa_remove(&t->idRoot, te); + UA_free(te); + } + UA_UNLOCK(&t->timerMutex); +} + +UA_DateTime +UA_Timer_process(UA_Timer *t, UA_DateTime nowMonotonic, + UA_TimerExecutionCallback executionCallback, + void *executionApplication) { + UA_LOCK(&t->timerMutex); + UA_TimerEntry *first; + while((first = (UA_TimerEntry*)aa_min(&t->root)) && + first->nextTime <= nowMonotonic) { + aa_remove(&t->root, first); + + /* Reinsert / remove to their new position first. Because the callback + * can interact with the zip tree and expects the same entries in the + * root and idRoot trees. */ + + if(first->interval == 0) { + aa_remove(&t->idRoot, first); + if(first->callback) { + UA_UNLOCK(&t->timerMutex); + executionCallback(executionApplication, first->callback, + first->application, first->data); + UA_LOCK(&t->timerMutex); + } + UA_free(first); + continue; + } + + /* Set the time for the next execution. Prevent an infinite loop by + * forcing the execution time in the next iteration. + * + * If the timer policy is "CurrentTime", then there is at least the + * interval between executions. This is used for Monitoreditems, for + * which the spec says: The sampling interval indicates the fastest rate + * at which the Server should sample its underlying source for data + * changes. (Part 4, 5.12.1.2) */ + first->nextTime += (UA_DateTime)first->interval; + if(first->nextTime < nowMonotonic) { + if(first->timerPolicy == UA_TIMER_HANDLE_CYCLEMISS_WITH_BASETIME) + first->nextTime = calculateNextTime(nowMonotonic, first->nextTime, + (UA_DateTime)first->interval); + else + first->nextTime = nowMonotonic + (UA_DateTime)first->interval; + } + + aa_insert(&t->root, first); + + if(!first->callback) + continue; + + /* Unlock the mutes before dropping into the callback. So that the timer + * itself can be edited within the callback. When we return, only the + * pointer to t must still exist. */ + UA_ApplicationCallback cb = first->callback; + void *app = first->application; + void *data = first->data; + UA_UNLOCK(&t->timerMutex); + executionCallback(executionApplication, cb, app, data); + UA_LOCK(&t->timerMutex); + } + + /* Return the timestamp of the earliest next callback */ + first = (UA_TimerEntry*)aa_min(&t->root); + UA_DateTime next = (first) ? first->nextTime : UA_INT64_MAX; + if(next < nowMonotonic) + next = nowMonotonic; + UA_UNLOCK(&t->timerMutex); + return next; +} + +void +UA_Timer_clear(UA_Timer *t) { + UA_LOCK(&t->timerMutex); + + /* Free all entries */ + UA_TimerEntry *top; + while((top = (UA_TimerEntry*)aa_min(&t->idRoot))) { + aa_remove(&t->idRoot, top); + UA_free(top); + } + + /* Reset the trees to avoid future access */ + t->root.root = NULL; + t->idRoot.root = NULL; + + UA_UNLOCK(&t->timerMutex); +#if UA_MULTITHREADING >= 100 + UA_LOCK_DESTROY(&t->timerMutex); +#endif +} + +/**** amalgamated original file "/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) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + * Copyright 2019 (c) Kalycito Infotech Private Limited + */ + + + +/* Hides some 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: + case UA_STATUSCODE_BADCERTIFICATEREVOKED: + 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]; + retval |= UA_encodeBinaryInternal(&header, + &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], + &bufPos, &bufEnd, NULL, NULL); + retval |= UA_encodeBinaryInternal(error, + &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE], + &bufPos, &bufEnd, NULL, NULL); + (void)retval; /* Encoding of these cannot fail */ + msg.length = header.messageSize; + connection->ua_send(connection, &msg); +} + +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 "/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-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + * Copyright 2018-2019 (c) HMS Industrial Networks AB (Author: Jonas Green) + */ + + + +#define UA_BITMASK_MESSAGETYPE 0x00ffffffu +#define UA_BITMASK_CHUNKTYPE 0xff000000u + +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 + +void UA_SecureChannel_init(UA_SecureChannel *channel, + const UA_ConnectionConfig *config) { + /* Linked lists are also initialized by zeroing out */ + memset(channel, 0, sizeof(UA_SecureChannel)); + channel->state = UA_SECURECHANNELSTATE_FRESH; + SIMPLEQ_INIT(&channel->completeChunks); + SIMPLEQ_INIT(&channel->decryptedChunks); + SLIST_INIT(&channel->sessions); + channel->config = *config; +} + +UA_StatusCode +UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel, + const UA_SecurityPolicy *securityPolicy, + const UA_ByteString *remoteCertificate) { + /* Is a policy already configured? */ + UA_CHECK_ERROR(!channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR, + securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, + "Security policy already configured"); + + /* Create the context */ + UA_StatusCode retval = securityPolicy->channelModule. + newContext(securityPolicy, remoteCertificate, &channel->channelContext); + retval |= UA_ByteString_copy(remoteCertificate, &channel->remoteCertificate); + UA_CHECK_STATUS_WARN(retval, return retval, securityPolicy->logger, + UA_LOGCATEGORY_SECURITYPOLICY, "Could not set up the SecureChannel context"); + + /* Compute the certificate thumbprint */ + UA_ByteString remoteCertificateThumbprint = {20, channel->remoteCertificateThumbprint}; + retval = securityPolicy->asymmetricModule. + makeCertificateThumbprint(securityPolicy, &channel->remoteCertificate, + &remoteCertificateThumbprint); + UA_CHECK_STATUS_WARN(retval, return retval, securityPolicy->logger, + UA_LOGCATEGORY_SECURITYPOLICY, "Could not create the certificate thumbprint"); + + /* Set the policy */ + channel->securityPolicy = securityPolicy; + return UA_STATUSCODE_GOOD; +} + +static void +UA_Chunk_delete(UA_Chunk *chunk) { + if(chunk->copied) + UA_ByteString_clear(&chunk->bytes); + UA_free(chunk); +} + +static void +deleteChunks(UA_ChunkQueue *queue) { + UA_Chunk *chunk; + while((chunk = SIMPLEQ_FIRST(queue))) { + SIMPLEQ_REMOVE_HEAD(queue, pointers); + UA_Chunk_delete(chunk); + } +} + +void +UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel) { + deleteChunks(&channel->completeChunks); + deleteChunks(&channel->decryptedChunks); + UA_ByteString_clear(&channel->incompleteChunk); +} + +void +UA_SecureChannel_close(UA_SecureChannel *channel) { + /* Set the status to closed */ + channel->state = UA_SECURECHANNELSTATE_CLOSED; + + /* Detach from the connection and close the connection */ + if(channel->connection) { + if(channel->connection->state != UA_CONNECTIONSTATE_CLOSED) + channel->connection->ua_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; + while((sh = SLIST_FIRST(&channel->sessions))) { + sh->channel = NULL; + SLIST_REMOVE_HEAD(&channel->sessions, next); + } + + /* Delete the channel context for the security policy */ + if(channel->securityPolicy) { + channel->securityPolicy->channelModule.deleteContext(channel->channelContext); + channel->securityPolicy = NULL; + channel->channelContext = NULL; + } + + /* Delete members */ + UA_ByteString_clear(&channel->remoteCertificate); + UA_ByteString_clear(&channel->localNonce); + UA_ByteString_clear(&channel->remoteNonce); + UA_ChannelSecurityToken_clear(&channel->securityToken); + UA_ChannelSecurityToken_clear(&channel->altSecurityToken); + UA_SecureChannel_deleteBuffered(channel); +} + +UA_StatusCode +UA_SecureChannel_processHELACK(UA_SecureChannel *channel, + const UA_TcpAcknowledgeMessage *remoteConfig) { + /* The lowest common version is used by both sides */ + if(channel->config.protocolVersion > remoteConfig->protocolVersion) + channel->config.protocolVersion = remoteConfig->protocolVersion; + + /* Can we receive the max send size? */ + if(channel->config.sendBufferSize > remoteConfig->receiveBufferSize) + channel->config.sendBufferSize = remoteConfig->receiveBufferSize; + + /* Can we send the max receive size? */ + if(channel->config.recvBufferSize > remoteConfig->sendBufferSize) + channel->config.recvBufferSize = remoteConfig->sendBufferSize; + + channel->config.remoteMaxMessageSize = remoteConfig->maxMessageSize; + channel->config.remoteMaxChunkCount = remoteConfig->maxChunkCount; + + /* Chunks of at least 8192 bytes must be permissible. + * See Part 6, Clause 6.7.1 */ + if(channel->config.recvBufferSize < 8192 || + channel->config.sendBufferSize < 8192 || + (channel->config.remoteMaxMessageSize != 0 && + channel->config.remoteMaxMessageSize < 8192)) + return UA_STATUSCODE_BADINTERNALERROR; + + channel->connection->state = UA_CONNECTIONSTATE_ESTABLISHED; + return UA_STATUSCODE_GOOD; +} + +/* 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) { + UA_CHECK(channel->securityMode != UA_MESSAGESECURITYMODE_INVALID, + return UA_STATUSCODE_BADSECURITYMODEREJECTED); + + const UA_SecurityPolicy *sp = channel->securityPolicy; + UA_Connection *conn = channel->connection; + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); + UA_CHECK_MEM(conn, return UA_STATUSCODE_BADINTERNALERROR); + + /* Allocate the message buffer */ + UA_ByteString buf = UA_BYTESTRING_NULL; + UA_StatusCode res = conn->getSendBuffer(conn, channel->config.sendBufferSize, &buf); + UA_CHECK_STATUS(res, return res); + + /* Restrict buffer to the available space for the payload */ + UA_Byte *buf_pos = buf.data; + const UA_Byte *buf_end = &buf.data[buf.length]; + hideBytesAsym(channel, &buf_pos, &buf_end); + + /* Encode the message type and content */ + res |= UA_NodeId_encodeBinary(&contentType->binaryEncodingId, &buf_pos, buf_end); + res |= UA_encodeBinaryInternal(content, contentType, + &buf_pos, &buf_end, NULL, NULL); + UA_CHECK_STATUS(res, conn->releaseSendBuffer(conn, &buf); return res); + + const size_t securityHeaderLength = calculateAsymAlgSecurityHeaderLength(channel); + +#ifdef UA_ENABLE_ENCRYPTION + /* Add padding to the chunk. Also pad if the securityMode is SIGN_ONLY, + * since we are using asymmetric communication to exchange keys and thus + * need to encrypt. */ + if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE) + padChunk(channel, &channel->securityPolicy->asymmetricModule.cryptoModule, + &buf.data[UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength], + &buf_pos); +#endif + + /* The total message length */ + 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 += sp->asymmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + + /* The total message length is known here which is why we encode the headers + * at this step and not earlier. */ + size_t encryptedLength = 0; + res = prependHeadersAsym(channel, buf.data, buf_end, total_length, + securityHeaderLength, requestId, &encryptedLength); + UA_CHECK_STATUS(res, conn->releaseSendBuffer(conn, &buf); return res); + +#ifdef UA_ENABLE_ENCRYPTION + res = signAndEncryptAsym(channel, pre_sig_length, &buf, + securityHeaderLength, total_length); + UA_CHECK_STATUS(res, conn->releaseSendBuffer(conn, &buf); return res); +#endif + + /* Send the message, the buffer is freed in the network layer */ + buf.length = encryptedLength; + res = conn->ua_send(conn, &buf); +#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS + res |= sendAsym_sendFailure; +#endif + return res; +} + +/* Will this chunk surpass the capacity of the SecureChannel for the message? */ +static UA_StatusCode +adjustCheckMessageLimitsSym(UA_MessageContext *mc, size_t bodyLength) { + mc->messageSizeSoFar += bodyLength; + mc->chunksSoFar++; + + UA_SecureChannel *channel = mc->channel; + if(mc->messageSizeSoFar > channel->config.localMaxMessageSize && + channel->config.localMaxMessageSize != 0) + return UA_STATUSCODE_BADRESPONSETOOLARGE; + + if(mc->chunksSoFar > channel->config.localMaxChunkCount && + channel->config.localMaxChunkCount != 0) + return UA_STATUSCODE_BADRESPONSETOOLARGE; + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +encodeHeadersSym(UA_MessageContext *mc, size_t totalLength) { + UA_SecureChannel *channel = mc->channel; + UA_Byte *header_pos = mc->messageBuffer.data; + + UA_TcpMessageHeader header; + header.messageTypeAndChunkType = mc->messageType; + header.messageSize = (UA_UInt32)totalLength; + if(mc->final) + header.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL; + else + header.messageTypeAndChunkType += UA_CHUNKTYPE_INTERMEDIATE; + + UA_SequenceHeader seqHeader; + seqHeader.requestId = mc->requestId; + seqHeader.sequenceNumber = UA_atomic_addUInt32(&channel->sendSequenceNumber, 1); + + UA_StatusCode res = UA_STATUSCODE_GOOD; + res |= UA_encodeBinaryInternal(&header, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], + &header_pos, &mc->buf_end, NULL, NULL); + res |= UA_UInt32_encodeBinary(&channel->securityToken.channelId, + &header_pos, mc->buf_end); + res |= UA_UInt32_encodeBinary(&channel->securityToken.tokenId, + &header_pos, mc->buf_end); + res |= UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], + &header_pos, &mc->buf_end, NULL, NULL); + return res; +} + +static UA_StatusCode +sendSymmetricChunk(UA_MessageContext *mc) { + UA_SecureChannel *channel = mc->channel; + const UA_SecurityPolicy *sp = channel->securityPolicy; + UA_Connection *connection = channel->connection; + UA_CHECK_MEM(connection, return UA_STATUSCODE_BADINTERNALERROR); + + /* The size of the message payload */ + size_t bodyLength = (uintptr_t)mc->buf_pos - + (uintptr_t)&mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]; + + /* Early-declare variables so we can use a goto in the error case */ + size_t total_length = 0; + size_t pre_sig_length = 0; + + /* Check if chunk exceeds the limits for the overall message */ + UA_StatusCode res = adjustCheckMessageLimitsSym(mc, bodyLength); + UA_CHECK_STATUS(res, goto error); + + UA_LOG_TRACE_CHANNEL(sp->logger, channel, + "Send from a symmetric message buffer of length %lu " + "a message of header+payload length of %lu", + (long unsigned int)mc->messageBuffer.length, + (long unsigned int) + ((uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data)); + +#ifdef UA_ENABLE_ENCRYPTION + /* Add padding if the message is encrypted */ + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + padChunk(channel, &sp->symmetricModule.cryptoModule, + &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH], + &mc->buf_pos); +#endif + + /* Compute the total message length */ + pre_sig_length = (uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data; + total_length = pre_sig_length; + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + total_length += sp->symmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + + UA_LOG_TRACE_CHANNEL(sp->logger, channel, + "Send from a symmetric message buffer of length %lu " + "a message of length %lu", + (long unsigned int)mc->messageBuffer.length, + (long unsigned int)total_length); + + /* Space for the padding and the signature have been reserved in setBufPos() */ + UA_assert(total_length <= channel->config.sendBufferSize); + + /* Adjust the buffer size of the network layer */ + mc->messageBuffer.length = total_length; + + /* Generate and encode the header for symmetric messages */ + res = encodeHeadersSym(mc, total_length); + UA_CHECK_STATUS(res, goto error); + +#ifdef UA_ENABLE_ENCRYPTION + /* Sign and encrypt the messge */ + res = signAndEncryptSym(mc, pre_sig_length, total_length); + UA_CHECK_STATUS(res, goto error); +#endif + + /* Send the chunk, the buffer is freed in the network layer */ + return connection->ua_send(channel->connection, &mc->messageBuffer); + + error: + /* Free the unused message buffer */ + connection->releaseSendBuffer(channel->connection, &mc->messageBuffer); + return res; +} + +/* Callback from the encoding layer. Send the chunk and replace the buffer. */ +static UA_StatusCode +sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos, const UA_Byte **buf_end) { + /* 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); + UA_CHECK_STATUS(retval, return retval); + + /* Set a new buffer for the next chunk */ + UA_Connection *connection = mc->channel->connection; + UA_CHECK_MEM(connection, return UA_STATUSCODE_BADINTERNALERROR); + + retval = connection->getSendBuffer(connection, mc->channel->config.sendBufferSize, + &mc->messageBuffer); + UA_CHECK_STATUS(retval, 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_CHECK(messageType == UA_MESSAGETYPE_MSG || messageType == UA_MESSAGETYPE_CLO, + return UA_STATUSCODE_BADINTERNALERROR); + + UA_Connection *connection = channel->connection; + UA_CHECK_MEM(connection, 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; + + /* Allocate the message buffer */ + UA_StatusCode retval = + connection->getSendBuffer(connection, channel->config.sendBufferSize, + &mc->messageBuffer); + UA_CHECK_STATUS(retval, 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 res = + UA_encodeBinaryInternal(content, contentType, &mc->buf_pos, &mc->buf_end, + sendSymmetricEncodingCallback, mc); + if(res != UA_STATUSCODE_GOOD && mc->messageBuffer.length > 0) + UA_MessageContext_abort(mc); + return res; +} + +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 || !channel->connection || !payload || !payloadType) + return UA_STATUSCODE_BADINTERNALERROR; + + if(channel->state != UA_SECURECHANNELSTATE_OPEN) + return UA_STATUSCODE_BADCONNECTIONCLOSED; + + if(channel->connection->state != UA_CONNECTIONSTATE_ESTABLISHED) + return UA_STATUSCODE_BADCONNECTIONCLOSED; + + UA_MessageContext mc; + UA_StatusCode retval = UA_MessageContext_begin(&mc, channel, requestId, messageType); + UA_CHECK_STATUS(retval, return retval); + + /* Assert's required for clang-analyzer */ + UA_assert(mc.buf_pos == &mc.messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]); + UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]); + + retval = UA_MessageContext_encode(&mc, &payloadType->binaryEncodingId, + &UA_TYPES[UA_TYPES_NODEID]); + UA_CHECK_STATUS(retval, return retval); + + retval = UA_MessageContext_encode(&mc, payload, payloadType); + UA_CHECK_STATUS(retval, return retval); + + return UA_MessageContext_finish(&mc); +} + +/********************************/ +/* Receive and Process Messages */ +/********************************/ + +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION +static UA_StatusCode +processSequenceNumberSym(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) { + /* Failure mode hook for unit tests */ +#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS + 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; +} + +#endif + +static UA_StatusCode +unpackPayloadOPN(UA_SecureChannel *channel, UA_Chunk *chunk, void *application) { + UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH); + size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */ + UA_UInt32 secureChannelId; + UA_StatusCode res = UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId); + UA_assert(res == UA_STATUSCODE_GOOD); + + UA_AsymmetricAlgorithmSecurityHeader asymHeader; + res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &asymHeader, + &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], NULL); + UA_CHECK_STATUS(res, return res); + + if(asymHeader.senderCertificate.length > 0) { + if(channel->certificateVerification) + res = channel->certificateVerification-> + verifyCertificate(channel->certificateVerification->context, + &asymHeader.senderCertificate); + else + res = UA_STATUSCODE_BADINTERNALERROR; + UA_CHECK_STATUS(res, goto error); + } + + /* New channel, create a security policy context and attach */ + if(!channel->securityPolicy) { + if(channel->processOPNHeader) + res = channel->processOPNHeader(application, channel, &asymHeader); + if(!channel->securityPolicy) + res = UA_STATUSCODE_BADINTERNALERROR; + UA_CHECK_STATUS(res, goto error); + } + + /* On the client side, take the SecureChannelId from the first response */ + if(secureChannelId != 0 && channel->securityToken.channelId == 0) + channel->securityToken.channelId = secureChannelId; + +#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + /* Check the ChannelId. Non-opened channels have the id zero. */ + if(secureChannelId != channel->securityToken.channelId) { + res = UA_STATUSCODE_BADSECURECHANNELIDINVALID; + goto error; + } +#endif + + /* Check the header */ + res = checkAsymHeader(channel, &asymHeader); + UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader); + UA_CHECK_STATUS(res, return res); + + /* Decrypt the chunk payload */ + res = decryptAndVerifyChunk(channel, &channel->securityPolicy->asymmetricModule.cryptoModule, + chunk->messageType, &chunk->bytes, offset); + UA_CHECK_STATUS(res, return res); + + /* Decode the SequenceHeader */ + UA_SequenceHeader sequenceHeader; + res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader, + &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL); + UA_CHECK_STATUS(res, return res); + + /* Set the sequence number for the channel from which to count up */ + channel->receiveSequenceNumber = sequenceHeader.sequenceNumber; + chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */ + + /* Use only the payload */ + chunk->bytes.data += offset; + chunk->bytes.length -= offset; + return UA_STATUSCODE_GOOD; + +error: + UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader); + return res; +} + +static UA_StatusCode +unpackPayloadMSG(UA_SecureChannel *channel, UA_Chunk *chunk) { + UA_CHECK_MEM(channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR); + + UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH); + size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */ + UA_UInt32 secureChannelId; + UA_UInt32 tokenId; /* SymmetricAlgorithmSecurityHeader */ + UA_StatusCode res = UA_STATUSCODE_GOOD; + res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId); + res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &tokenId); + UA_assert(offset == UA_SECURECHANNEL_MESSAGE_MIN_LENGTH); + UA_assert(res == UA_STATUSCODE_GOOD); + +#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + /* Check the ChannelId. Non-opened channels have the id zero. */ + UA_CHECK(secureChannelId == channel->securityToken.channelId, + return UA_STATUSCODE_BADSECURECHANNELIDINVALID); +#endif + + /* Check (and revolve) the SecurityToken */ + res = checkSymHeader(channel, tokenId); + UA_CHECK_STATUS(res, return res); + + /* Decrypt the chunk payload */ + res = decryptAndVerifyChunk(channel, &channel->securityPolicy->symmetricModule.cryptoModule, + chunk->messageType, &chunk->bytes, offset); + UA_CHECK_STATUS(res, return res); + + /* Check the sequence number. Skip sequence number checking for fuzzer to + * improve coverage */ + UA_SequenceHeader sequenceHeader; + res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader, + &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL); +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + res |= processSequenceNumberSym(channel, sequenceHeader.sequenceNumber); +#endif + UA_CHECK_STATUS(res, return res); + + chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */ + + /* Use only the payload */ + chunk->bytes.data += offset; + chunk->bytes.length -= offset; + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +assembleProcessMessage(UA_SecureChannel *channel, void *application, + UA_ProcessMessageCallback callback) { + UA_Chunk *chunk = SIMPLEQ_FIRST(&channel->decryptedChunks); + UA_assert(chunk != NULL); + + if(chunk->chunkType == UA_CHUNKTYPE_FINAL) { + SIMPLEQ_REMOVE_HEAD(&channel->decryptedChunks, pointers); + UA_assert(chunk->chunkType == UA_CHUNKTYPE_FINAL); + UA_StatusCode retval = callback(application, channel, chunk->messageType, chunk->requestId, &chunk->bytes); + UA_Chunk_delete(chunk); + return retval; + } + + UA_UInt32 requestId = chunk->requestId; + UA_MessageType messageType = chunk->messageType; + UA_ChunkType chunkType = chunk->chunkType; + UA_assert(chunkType == UA_CHUNKTYPE_INTERMEDIATE); + + size_t messageSize = 0; + SIMPLEQ_FOREACH(chunk, &channel->decryptedChunks, pointers) { + /* Consistency check */ + if(requestId != chunk->requestId) + return UA_STATUSCODE_BADINTERNALERROR; + if(chunkType != chunk->chunkType && chunk->chunkType != UA_CHUNKTYPE_FINAL) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + if(chunk->messageType != messageType) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + + /* Sum up the lengths */ + messageSize += chunk->bytes.length; + if(chunk->chunkType == UA_CHUNKTYPE_FINAL) + break; + } + + /* Allocate memory for the full message */ + UA_ByteString payload; + UA_StatusCode res = UA_ByteString_allocBuffer(&payload, messageSize); + UA_CHECK_STATUS(res, return res); + + /* Assemble the full message */ + size_t offset = 0; + while(true) { + chunk = SIMPLEQ_FIRST(&channel->decryptedChunks); + memcpy(&payload.data[offset], chunk->bytes.data, chunk->bytes.length); + offset += chunk->bytes.length; + SIMPLEQ_REMOVE_HEAD(&channel->decryptedChunks, pointers); + UA_ChunkType ct = chunk->chunkType; + UA_Chunk_delete(chunk); + if(ct == UA_CHUNKTYPE_FINAL) + break; + } + + /* Process the assembled message */ + UA_StatusCode retval = callback(application, channel, messageType, requestId, &payload); + UA_ByteString_clear(&payload); + return retval; +} + +static UA_StatusCode +persistCompleteChunks(UA_ChunkQueue *queue) { + UA_Chunk *chunk; + SIMPLEQ_FOREACH(chunk, queue, pointers) { + if(chunk->copied) + continue; + UA_ByteString copy; + UA_StatusCode retval = UA_ByteString_copy(&chunk->bytes, ©); + if(retval != UA_STATUSCODE_GOOD) + return retval; + chunk->bytes = copy; + chunk->copied = true; + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +persistIncompleteChunk(UA_SecureChannel *channel, const UA_ByteString *buffer, + size_t offset) { + UA_assert(channel->incompleteChunk.length == 0); + UA_assert(offset < buffer->length); + size_t length = buffer->length - offset; + UA_StatusCode retval = UA_ByteString_allocBuffer(&channel->incompleteChunk, length); + if(retval != UA_STATUSCODE_GOOD) + return retval; + memcpy(channel->incompleteChunk.data, &buffer->data[offset], length); + return UA_STATUSCODE_GOOD; +} + +/* Processes chunks and puts them into the payloads queue. Once a final chunk is + * put into the queue, the message is assembled and the callback is called. The + * queue will be cleared for the next message. */ +static UA_StatusCode +processChunks(UA_SecureChannel *channel, void *application, + UA_ProcessMessageCallback callback) { + UA_Chunk *chunk; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + while((chunk = SIMPLEQ_FIRST(&channel->completeChunks))) { + /* Remove from the complete-chunk queue */ + SIMPLEQ_REMOVE_HEAD(&channel->completeChunks, pointers); + + /* Check, decrypt and unpack the payload */ + if(chunk->messageType == UA_MESSAGETYPE_OPN) { + if(channel->state != UA_SECURECHANNELSTATE_OPEN && + channel->state != UA_SECURECHANNELSTATE_OPN_SENT && + channel->state != UA_SECURECHANNELSTATE_ACK_SENT) + retval = UA_STATUSCODE_BADINVALIDSTATE; + else + retval = unpackPayloadOPN(channel, chunk, application); + } else if(chunk->messageType == UA_MESSAGETYPE_MSG || + chunk->messageType == UA_MESSAGETYPE_CLO) { + if(channel->state == UA_SECURECHANNELSTATE_CLOSED) + retval = UA_STATUSCODE_BADSECURECHANNELCLOSED; + else + retval = unpackPayloadMSG(channel, chunk); + } else { + chunk->bytes.data += UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; + chunk->bytes.length -= UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; + } + + if(retval != UA_STATUSCODE_GOOD) { + UA_Chunk_delete(chunk); + return retval; + } + + /* Add to the decrypted queue */ + SIMPLEQ_INSERT_TAIL(&channel->decryptedChunks, chunk, pointers); + + /* Check the resource limits */ + channel->decryptedChunksCount++; + channel->decryptedChunksLength += chunk->bytes.length; + if((channel->config.localMaxChunkCount != 0 && + channel->decryptedChunksCount > channel->config.localMaxChunkCount) || + (channel->config.localMaxMessageSize != 0 && + channel->decryptedChunksLength > channel->config.localMaxMessageSize)) { + return UA_STATUSCODE_BADTCPMESSAGETOOLARGE; + } + + /* Continue */ + if(chunk->chunkType != UA_CHUNKTYPE_FINAL) + continue; + + /* The decrypted queue contains a full message. Process it. */ + retval = assembleProcessMessage(channel, application, callback); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Reset the counters */ + channel->decryptedChunksCount = 0; + channel->decryptedChunksLength = 0; + } + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +extractCompleteChunk(UA_SecureChannel *channel, const UA_ByteString *buffer, + size_t *offset, UA_Boolean *done) { + /* At least 8 byte needed for the header. Wait for the next chunk. */ + size_t initial_offset = *offset; + size_t remaining = buffer->length - initial_offset; + if(remaining < UA_SECURECHANNEL_MESSAGEHEADER_LENGTH) { + *done = true; + return UA_STATUSCODE_GOOD; + } + + /* Decoding cannot fail */ + UA_TcpMessageHeader hdr; + UA_StatusCode res = + UA_decodeBinaryInternal(buffer, &initial_offset, &hdr, + &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], NULL); + UA_assert(res == UA_STATUSCODE_GOOD); + (void)res; /* pacify compilers if assert is ignored */ + UA_MessageType msgType = (UA_MessageType) + (hdr.messageTypeAndChunkType & UA_BITMASK_MESSAGETYPE); + UA_ChunkType chunkType = (UA_ChunkType) + (hdr.messageTypeAndChunkType & UA_BITMASK_CHUNKTYPE); + + /* The message size is not allowed */ + if(hdr.messageSize < UA_SECURECHANNEL_MESSAGE_MIN_LENGTH) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + if(hdr.messageSize > channel->config.recvBufferSize) + return UA_STATUSCODE_BADTCPMESSAGETOOLARGE; + + /* Incomplete chunk */ + if(hdr.messageSize > remaining) { + *done = true; + return UA_STATUSCODE_GOOD; + } + + /* ByteString with only this chunk. */ + UA_ByteString chunkPayload; + chunkPayload.data = &buffer->data[*offset]; + chunkPayload.length = hdr.messageSize; + + if(msgType == UA_MESSAGETYPE_HEL || msgType == UA_MESSAGETYPE_ACK || + msgType == UA_MESSAGETYPE_ERR || msgType == UA_MESSAGETYPE_OPN) { + if(chunkType != UA_CHUNKTYPE_FINAL) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } else { + /* Only messages on SecureChannel-level with symmetric encryption afterwards */ + if(msgType != UA_MESSAGETYPE_MSG && + msgType != UA_MESSAGETYPE_CLO) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + + /* Check the chunk type before decrypting */ + if(chunkType != UA_CHUNKTYPE_FINAL && + chunkType != UA_CHUNKTYPE_INTERMEDIATE && + chunkType != UA_CHUNKTYPE_ABORT) + return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + } + + /* Add the chunk; forward the offset */ + *offset += hdr.messageSize; + UA_Chunk *chunk = (UA_Chunk*)UA_malloc(sizeof(UA_Chunk)); + UA_CHECK_MEM(chunk, return UA_STATUSCODE_BADOUTOFMEMORY); + + chunk->bytes = chunkPayload; + chunk->messageType = msgType; + chunk->chunkType = chunkType; + chunk->requestId = 0; + chunk->copied = false; + + SIMPLEQ_INSERT_TAIL(&channel->completeChunks, chunk, pointers); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_SecureChannel_processBuffer(UA_SecureChannel *channel, void *application, + UA_ProcessMessageCallback callback, + const UA_ByteString *buffer) { + /* Prepend the incomplete last chunk. This is usually done in the + * networklayer. But we test for a buffered incomplete chunk here again to + * work around "lazy" network layers. */ + UA_ByteString appended = channel->incompleteChunk; + if(appended.length > 0) { + channel->incompleteChunk = UA_BYTESTRING_NULL; + UA_Byte *t = (UA_Byte*)UA_realloc(appended.data, appended.length + buffer->length); + UA_CHECK_MEM(t, UA_ByteString_clear(&appended); + return UA_STATUSCODE_BADOUTOFMEMORY); + memcpy(&t[appended.length], buffer->data, buffer->length); + appended.data = t; + appended.length += buffer->length; + buffer = &appended; + } + + /* Loop over the received chunks */ + size_t offset = 0; + UA_Boolean done = false; + UA_StatusCode res; + while(!done) { + res = extractCompleteChunk(channel, buffer, &offset, &done); + UA_CHECK_STATUS(res, goto cleanup); + } + + /* Buffer half-received chunk. Before processing the messages so that + * processing is reentrant. */ + if(offset < buffer->length) { + res = persistIncompleteChunk(channel, buffer, offset); + UA_CHECK_STATUS(res, goto cleanup); + } + + /* Process whatever we can. Chunks of completed and processed messages are + * removed. */ + res = processChunks(channel, application, callback); + UA_CHECK_STATUS(res, goto cleanup); + + /* Persist full chunks that still point to the buffer. Can only return + * UA_STATUSCODE_BADOUTOFMEMORY as an error code. So merging res works. */ + res |= persistCompleteChunks(&channel->completeChunks); + res |= persistCompleteChunks(&channel->decryptedChunks); + + cleanup: + UA_ByteString_clear(&appended); + return res; +} + +UA_StatusCode +UA_SecureChannel_receive(UA_SecureChannel *channel, void *application, + UA_ProcessMessageCallback callback, UA_UInt32 timeout) { + UA_Connection *connection = channel->connection; + UA_CHECK_MEM(connection, return UA_STATUSCODE_BADINTERNALERROR); + + /* Listen for messages to arrive */ + UA_ByteString buffer = UA_BYTESTRING_NULL; + UA_StatusCode retval = connection->ua_recv(connection, &buffer, timeout); + UA_CHECK_STATUS(retval, return retval); + + /* Try to process one complete chunk */ + retval = UA_SecureChannel_processBuffer(channel, application, callback, &buffer); + connection->releaseRecvBuffer(connection, &buffer); + return retval; +} + +/**** amalgamated original file "/src/ua_securechannel_crypto.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + */ + + + +UA_StatusCode +UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel) { + const UA_SecurityPolicy *sp = channel->securityPolicy; + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); + UA_LOG_DEBUG_CHANNEL(sp->logger, channel, "Generating new local nonce"); + + /* Is the length of the previous nonce correct? */ + size_t nonceLength = sp->symmetricModule.secureChannelNonceLength; + if(channel->localNonce.length != nonceLength) { + UA_ByteString_clear(&channel->localNonce); + UA_StatusCode res = UA_ByteString_allocBuffer(&channel->localNonce, nonceLength); + UA_CHECK_STATUS(res, return res); + } + + /* Generate the nonce */ + return sp->symmetricModule.generateNonce(sp->policyContext, &channel->localNonce); +} + +UA_StatusCode +UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *channel) { + const UA_SecurityPolicy *sp = channel->securityPolicy; + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); + UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Generating new local keys"); + + void *cc = channel->channelContext; + const UA_SecurityPolicyChannelModule *cm = &sp->channelModule; + const UA_SecurityPolicySymmetricModule *sm = &sp->symmetricModule; + const UA_SecurityPolicyCryptoModule *crm = &sm->cryptoModule; + + /* Generate symmetric key buffer of the required length. The block size is + * identical for local/remote. */ + UA_ByteString buf; + size_t encrKL = crm->encryptionAlgorithm.getLocalKeyLength(cc); + size_t encrBS = crm->encryptionAlgorithm.getRemoteBlockSize(cc); + size_t signKL = crm->signatureAlgorithm.getLocalKeyLength(cc); + if(encrBS + signKL + encrKL == 0) + return UA_STATUSCODE_GOOD; /* No keys to generate */ + + UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, encrBS + signKL + encrKL); + UA_CHECK_STATUS(retval, return retval); + UA_ByteString localSigningKey = {signKL, buf.data}; + UA_ByteString localEncryptingKey = {encrKL, &buf.data[signKL]}; + UA_ByteString localIv = {encrBS, &buf.data[signKL + encrKL]}; + + /* Generate key */ + retval = sm->generateKey(sp->policyContext, &channel->remoteNonce, + &channel->localNonce, &buf); + UA_CHECK_STATUS(retval, goto error); + + /* Set the channel context */ + retval |= cm->setLocalSymSigningKey(cc, &localSigningKey); + retval |= cm->setLocalSymEncryptingKey(cc, &localEncryptingKey); + retval |= cm->setLocalSymIv(cc, &localIv); + + error: + UA_CHECK_STATUS(retval, UA_LOG_WARNING_CHANNEL(sp->logger, channel, + "Could not generate local keys (statuscode: %s)", + UA_StatusCode_name(retval))); + UA_ByteString_clear(&buf); + return retval; +} + +UA_StatusCode +generateRemoteKeys(const UA_SecureChannel *channel) { + const UA_SecurityPolicy *sp = channel->securityPolicy; + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); + UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Generating new remote keys"); + + void *cc = channel->channelContext; + const UA_SecurityPolicyChannelModule *cm = &sp->channelModule; + const UA_SecurityPolicySymmetricModule *sm = &sp->symmetricModule; + const UA_SecurityPolicyCryptoModule *crm = &sm->cryptoModule; + + /* Generate symmetric key buffer of the required length */ + UA_ByteString buf; + size_t encrKL = crm->encryptionAlgorithm.getRemoteKeyLength(cc); + size_t encrBS = crm->encryptionAlgorithm.getRemoteBlockSize(cc); + size_t signKL = crm->signatureAlgorithm.getRemoteKeyLength(cc); + if(encrBS + signKL + encrKL == 0) + return UA_STATUSCODE_GOOD; /* No keys to generate */ + + UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, encrBS + signKL + encrKL); + UA_CHECK_STATUS(retval, return retval); + UA_ByteString remoteSigningKey = {signKL, buf.data}; + UA_ByteString remoteEncryptingKey = {encrKL, &buf.data[signKL]}; + UA_ByteString remoteIv = {encrBS, &buf.data[signKL + encrKL]}; + + /* Generate key */ + retval = sm->generateKey(sp->policyContext, &channel->localNonce, + &channel->remoteNonce, &buf); + UA_CHECK_STATUS(retval, goto error); + + /* Set the channel context */ + retval |= cm->setRemoteSymSigningKey(cc, &remoteSigningKey); + retval |= cm->setRemoteSymEncryptingKey(cc, &remoteEncryptingKey); + retval |= cm->setRemoteSymIv(cc, &remoteIv); + + error: + UA_CHECK_STATUS(retval, UA_LOG_WARNING_CHANNEL(sp->logger, channel, + "Could not generate remote keys (statuscode: %s)", + UA_StatusCode_name(retval))); + UA_ByteString_clear(&buf); + return retval; +} + +/***************************/ +/* Send Asymmetric Message */ +/***************************/ + +/* The length of the static header content */ +#define UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH 12 + +size_t +calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel) { + const UA_SecurityPolicy *sp = channel->securityPolicy; + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); + + size_t asymHeaderLength = UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH + + sp->policyUri.length; + if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) + return asymHeaderLength; + + /* OPN is always encrypted even if the mode is sign only */ + asymHeaderLength += 20; /* Thumbprints are always 20 byte long */ + asymHeaderLength += sp->localCertificate.length; + return asymHeaderLength; +} + +UA_StatusCode +prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos, + const UA_Byte *buf_end, size_t totalLength, + size_t securityHeaderLength, UA_UInt32 requestId, + size_t *const encryptedLength) { + const UA_SecurityPolicy *sp = channel->securityPolicy; + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); + + if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) { + *encryptedLength = totalLength; + } else { + size_t dataToEncryptLength = totalLength - + (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength); + size_t plainTextBlockSize = sp->asymmetricModule.cryptoModule. + encryptionAlgorithm.getRemotePlainTextBlockSize(channel->channelContext); + size_t encryptedBlockSize = sp->asymmetricModule.cryptoModule. + encryptionAlgorithm.getRemoteBlockSize(channel->channelContext); + + /* Padding always fills up the last block */ + UA_assert(dataToEncryptLength % plainTextBlockSize == 0); + size_t blocks = dataToEncryptLength / plainTextBlockSize; + *encryptedLength = totalLength + blocks * (encryptedBlockSize - plainTextBlockSize); + } + + UA_TcpMessageHeader messageHeader; + messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL; + messageHeader.messageSize = (UA_UInt32)*encryptedLength; + UA_UInt32 secureChannelId = channel->securityToken.channelId; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + retval |= UA_encodeBinaryInternal(&messageHeader, + &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], + &header_pos, &buf_end, NULL, NULL); + retval |= UA_UInt32_encodeBinary(&secureChannelId, &header_pos, buf_end); + UA_CHECK_STATUS(retval, return retval); + + UA_AsymmetricAlgorithmSecurityHeader asymHeader; + UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); + asymHeader.securityPolicyUri = sp->policyUri; + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || + channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + asymHeader.senderCertificate = sp->localCertificate; + asymHeader.receiverCertificateThumbprint.length = 20; + asymHeader.receiverCertificateThumbprint.data = channel->remoteCertificateThumbprint; + } + retval = UA_encodeBinaryInternal(&asymHeader, + &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], + &header_pos, &buf_end, NULL, NULL); + UA_CHECK_STATUS(retval, return retval); + + UA_SequenceHeader seqHeader; + seqHeader.requestId = requestId; + seqHeader.sequenceNumber = UA_atomic_addUInt32(&channel->sendSequenceNumber, 1); + retval = UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], + &header_pos, &buf_end, NULL, NULL); + return retval; +} + +void +hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start, + const UA_Byte **buf_end) { + /* Set buf_start to the beginning of the payload body */ + *buf_start += UA_SECURECHANNEL_CHANNELHEADER_LENGTH; + *buf_start += calculateAsymAlgSecurityHeaderLength(channel); + *buf_start += UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH; + +#ifdef UA_ENABLE_ENCRYPTION + if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) + return; + + /* Make space for the certificate */ + const UA_SecurityPolicy *sp = channel->securityPolicy; + *buf_end -= sp->asymmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + + /* Block sizes depend on the remote key (certificate) */ + size_t plainTextBlockSize = sp->asymmetricModule.cryptoModule. + encryptionAlgorithm.getRemotePlainTextBlockSize(channel->channelContext); + size_t encryptedBlockSize = sp->asymmetricModule.cryptoModule. + encryptionAlgorithm.getRemoteBlockSize(channel->channelContext); + UA_Boolean extraPadding = (sp->asymmetricModule.cryptoModule.encryptionAlgorithm. + getRemoteKeyLength(channel->channelContext) > 2048); + + /* Compute the maximum number of encrypted blocks that can fit entirely + * before the signature. From that compute the maximum usable plaintext + * size. */ + size_t maxEncrypted = (size_t)(*buf_end - *buf_start) + + UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH; + size_t max_blocks = maxEncrypted / encryptedBlockSize; + size_t paddingBytes = (UA_LIKELY(!extraPadding)) ? 1u : 2u; + *buf_end = *buf_start + (max_blocks * plainTextBlockSize) - + UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH - paddingBytes; +#endif +} + +#ifdef UA_ENABLE_ENCRYPTION + +/* Assumes that pos can be advanced to the end of the current block */ +void +padChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cm, + const UA_Byte *start, UA_Byte **pos) { + const size_t bytesToWrite = (uintptr_t)*pos - (uintptr_t)start; + size_t signatureSize = cm->signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + size_t plainTextBlockSize = cm->encryptionAlgorithm. + getRemotePlainTextBlockSize(channel->channelContext); + UA_Boolean extraPadding = (cm->encryptionAlgorithm. + getRemoteKeyLength(channel->channelContext) > 2048); + size_t paddingBytes = (UA_LIKELY(!extraPadding)) ? 1u : 2u; + + size_t lastBlock = ((bytesToWrite + signatureSize + paddingBytes) % plainTextBlockSize); + size_t paddingLength = (lastBlock != 0) ? plainTextBlockSize - lastBlock : 0; + + UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel, + "Add %lu bytes of padding plus %lu padding size bytes", + (long unsigned int)paddingLength, + (long unsigned int)paddingBytes); + + /* Write the padding. This is <= because the paddingSize byte also has to be + * written */ + UA_Byte paddingByte = (UA_Byte)paddingLength; + for(UA_UInt16 i = 0; i <= paddingLength; ++i) { + **pos = paddingByte; + ++*pos; + } + + /* Write the extra padding byte if required */ + if(extraPadding) { + **pos = (UA_Byte)(paddingLength >> 8u); + ++*pos; + } +} + +UA_StatusCode +signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength, + UA_ByteString *buf, size_t securityHeaderLength, + size_t totalLength) { + if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && + channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + return UA_STATUSCODE_GOOD; + + /* Sign message */ + const UA_SecurityPolicy *sp = channel->securityPolicy; + const UA_ByteString dataToSign = {preSignLength, buf->data}; + size_t sigsize = sp->asymmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + UA_ByteString signature = {sigsize, buf->data + preSignLength}; + UA_StatusCode retval = sp->asymmetricModule.cryptoModule.signatureAlgorithm. + sign(channel->channelContext, &dataToSign, &signature); + UA_CHECK_STATUS(retval, return retval); + + /* Specification part 6, 6.7.4: The OpenSecureChannel Messages are + * signed and encrypted if the SecurityMode is not None (even if the + * SecurityMode is SignOnly). */ + size_t unencrypted_length = + UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength; + UA_ByteString dataToEncrypt = {totalLength - unencrypted_length, + &buf->data[unencrypted_length]}; + return sp->asymmetricModule.cryptoModule.encryptionAlgorithm. + encrypt(channel->channelContext, &dataToEncrypt); +} + +/**************************/ +/* Send Symmetric Message */ +/**************************/ + +UA_StatusCode +signAndEncryptSym(UA_MessageContext *messageContext, + size_t preSigLength, size_t totalLength) { + const UA_SecureChannel *channel = messageContext->channel; + if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) + return UA_STATUSCODE_GOOD; + + /* Sign */ + const UA_SecurityPolicy *sp = channel->securityPolicy; + UA_ByteString dataToSign = messageContext->messageBuffer; + dataToSign.length = preSigLength; + UA_ByteString signature; + signature.length = sp->symmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + signature.data = messageContext->buf_pos; + UA_StatusCode res = sp->symmetricModule.cryptoModule.signatureAlgorithm. + sign(channel->channelContext, &dataToSign, &signature); + UA_CHECK_STATUS(res, return res); + + if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) + return UA_STATUSCODE_GOOD; + + /* Encrypt */ + UA_ByteString dataToEncrypt; + dataToEncrypt.data = messageContext->messageBuffer.data + + UA_SECURECHANNEL_CHANNELHEADER_LENGTH + + UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH; + dataToEncrypt.length = totalLength - + (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + + UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH); + return sp->symmetricModule.cryptoModule.encryptionAlgorithm. + encrypt(channel->channelContext, &dataToEncrypt); +} + +#endif /* UA_ENABLE_ENCRYPTION */ + +void +setBufPos(UA_MessageContext *mc) { + /* Forward the data pointer so that the payload is encoded after the message + * header. This has to be a symmetric message because OPN (with asymmetric + * encryption) does not support chunking. */ + mc->buf_pos = &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]; + mc->buf_end = &mc->messageBuffer.data[mc->messageBuffer.length]; + +#ifdef UA_ENABLE_ENCRYPTION + if(mc->channel->securityMode == UA_MESSAGESECURITYMODE_NONE) + return; + + const UA_SecureChannel *channel = mc->channel; + const UA_SecurityPolicy *sp = channel->securityPolicy; + size_t sigsize = sp->symmetricModule.cryptoModule.signatureAlgorithm. + getLocalSignatureSize(channel->channelContext); + size_t plainBlockSize = sp->symmetricModule.cryptoModule. + encryptionAlgorithm.getRemotePlainTextBlockSize(channel->channelContext); + + /* Assuming that for symmetric encryption the plainTextBlockSize == + * cypherTextBlockSize. For symmetric encryption the remote/local block + * sizes are identical. */ + UA_assert(sp->symmetricModule.cryptoModule.encryptionAlgorithm. + getRemoteBlockSize(channel->channelContext) == plainBlockSize); + + /* Leave enough space for the signature and padding */ + mc->buf_end -= sigsize; + mc->buf_end -= mc->messageBuffer.length % plainBlockSize; + + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + /* Reserve space for the padding bytes */ + UA_Boolean extraPadding = + (sp->symmetricModule.cryptoModule.encryptionAlgorithm. + getRemoteKeyLength(channel->channelContext) > 2048); + mc->buf_end -= (UA_LIKELY(!extraPadding)) ? 1 : 2; + } + + UA_LOG_TRACE_CHANNEL(sp->logger, channel, + "Prepare a symmetric message buffer of length %lu " + "with a usable maximum payload length of %lu", + (long unsigned)mc->messageBuffer.length, + (long unsigned)((uintptr_t)mc->buf_end - + (uintptr_t)mc->messageBuffer.data)); +#endif +} + +/****************************/ +/* Process a received Chunk */ +/****************************/ + +static size_t +decodePadding(const UA_SecureChannel *channel, + const UA_SecurityPolicyCryptoModule *cryptoModule, + const UA_ByteString *chunk, size_t sigsize) { + /* Read the byte with the padding size */ + size_t paddingSize = chunk->data[chunk->length - sigsize - 1]; + + /* Extra padding size */ + if(cryptoModule->encryptionAlgorithm. + getLocalKeyLength(channel->channelContext) > 2048) { + paddingSize <<= 8u; + paddingSize += chunk->data[chunk->length - sigsize - 2]; + paddingSize += 1; /* Extra padding byte itself */ + } + + /* Add one since the paddingSize byte itself needs to be removed as well */ + return paddingSize + 1; +} + +static UA_StatusCode +verifySignature(const UA_SecureChannel *channel, + const UA_SecurityPolicyCryptoModule *cryptoModule, + const UA_ByteString *chunk, size_t sigsize) { + UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel, + "Verifying chunk signature"); + UA_CHECK(sigsize < chunk->length, return UA_STATUSCODE_BADSECURITYCHECKSFAILED); + const UA_ByteString content = {chunk->length - sigsize, chunk->data}; + const UA_ByteString sig = {sigsize, chunk->data + chunk->length - sigsize}; + UA_StatusCode retval = cryptoModule->signatureAlgorithm. + verify(channel->channelContext, &content, &sig); +#ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS + retval |= decrypt_verifySignatureFailure; +#endif + return retval; +} + +/* Sets the payload to a pointer inside the chunk buffer. Returns the requestId + * and the sequenceNumber */ +UA_StatusCode +decryptAndVerifyChunk(const UA_SecureChannel *channel, + const UA_SecurityPolicyCryptoModule *cryptoModule, + UA_MessageType messageType, UA_ByteString *chunk, + size_t offset) { + /* Decrypt the chunk */ + UA_StatusCode res = UA_STATUSCODE_GOOD; + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT || + messageType == UA_MESSAGETYPE_OPN) { + UA_ByteString cipher = {chunk->length - offset, chunk->data + offset}; + res = cryptoModule->encryptionAlgorithm.decrypt(channel->channelContext, &cipher); + UA_CHECK_STATUS(res, return res); + chunk->length = cipher.length + offset; + } + + /* Does the message have a signature? */ + if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN && + channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT && + messageType != UA_MESSAGETYPE_OPN) + return UA_STATUSCODE_GOOD; + + /* Verify the chunk signature */ + size_t sigsize = cryptoModule->signatureAlgorithm. + getRemoteSignatureSize(channel->channelContext); + res = verifySignature(channel, cryptoModule, chunk, sigsize); + UA_CHECK_STATUS(res, + UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, + "Could not verify the signature"); return res); + + /* Compute the padding if the payload as encrypted */ + size_t padSize = 0; + if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT || + (messageType == UA_MESSAGETYPE_OPN && + cryptoModule->encryptionAlgorithm.uri.length > 0)) { + padSize = decodePadding(channel, cryptoModule, chunk, sigsize); + UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel, + "Calculated padding size to be %lu", + (long unsigned)padSize); + } + + /* Verify the content length. The encrypted payload has to be at least 9 + * bytes long: 8 byte for the SequenceHeader and one byte for the actual + * message */ + UA_CHECK(offset + padSize + sigsize + 9 < chunk->length, + UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, + "Impossible padding value"); + return UA_STATUSCODE_BADSECURITYCHECKSFAILED); + + /* Hide the signature and padding */ + chunk->length -= (sigsize + padSize); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +checkAsymHeader(UA_SecureChannel *channel, + const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) { + const UA_SecurityPolicy *sp = channel->securityPolicy; + if(!UA_ByteString_equal(&sp->policyUri, &asymHeader->securityPolicyUri)) + return UA_STATUSCODE_BADSECURITYPOLICYREJECTED; + + return sp->asymmetricModule. + compareCertificateThumbprint(sp, &asymHeader->receiverCertificateThumbprint); + + /* The certificate in the header is verified via the configured PKI plugin + * as certificateVerification.verifyCertificate(...). We cannot do it here + * because the client/server context is needed. */ +} + +UA_StatusCode +checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId) { + /* If no match, try to revolve to the next token after a + * RenewSecureChannel */ + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_ChannelSecurityToken *token = &channel->securityToken; + switch(channel->renewState) { + case UA_SECURECHANNELRENEWSTATE_NORMAL: + case UA_SECURECHANNELRENEWSTATE_SENT: + default: + break; + + case UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER: + /* Old token still in use */ + if(tokenId == channel->securityToken.tokenId) + break; + + /* Not the new token */ + UA_CHECK(tokenId == channel->altSecurityToken.tokenId, + UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, + "Unknown SecurityToken"); + return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN); + + /* Roll over to the new token, generate new local and remote keys */ + channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL; + channel->securityToken = channel->altSecurityToken; + UA_ChannelSecurityToken_init(&channel->altSecurityToken); + retval |= UA_SecureChannel_generateLocalKeys(channel); + retval |= generateRemoteKeys(channel); + UA_CHECK_STATUS(retval, return retval); + break; + + case UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT: + /* The server is still using the old token. That's okay. */ + if(tokenId == channel->altSecurityToken.tokenId) { + token = &channel->altSecurityToken; + break; + } + + /* Not the new token */ + UA_CHECK(tokenId == channel->securityToken.tokenId, + UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, + "Unknown SecurityToken"); + return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN); + + /* The remote server uses the new token for the first time. Delete the + * old token and roll the remote key over. The local key already uses + * the nonce pair from the last OPN exchange. */ + channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL; + UA_ChannelSecurityToken_init(&channel->altSecurityToken); + retval = generateRemoteKeys(channel); + UA_CHECK_STATUS(retval, return retval); + } + + UA_DateTime timeout = token->createdAt + (token->revisedLifetime * UA_DATETIME_MSEC); + if(channel->state == UA_SECURECHANNELSTATE_OPEN && + timeout < UA_DateTime_nowMonotonic()) { + UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel, + "SecurityToken timed out"); + UA_SecureChannel_close(channel); + return UA_STATUSCODE_BADSECURECHANNELCLOSED; + } + + return UA_STATUSCODE_GOOD; +} + +/**** amalgamated original file "/src/server/ua_session.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA + * Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green) + */ + +#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); + TAILQ_INIT(&session->subscriptions); +#endif +} + +void UA_Session_clear(UA_Session *session, UA_Server* server) { + UA_LOCK_ASSERT(&server->serviceMutex, 1); + + /* Remove all Subscriptions. This may send out remaining publish + * responses. */ +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_Subscription *sub, *tempsub; + TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, tempsub) { + UA_Subscription_delete(server, sub); + } +#endif + + UA_Session_detachFromSecureChannel(session); + UA_ApplicationDescription_clear(&session->clientDescription); + UA_NodeId_clear(&session->header.authenticationToken); + UA_NodeId_clear(&session->sessionId); + UA_String_clear(&session->sessionName); + UA_ByteString_clear(&session->serverNonce); + struct ContinuationPoint *cp, *next = session->continuationPoints; + while((cp = next)) { + next = ContinuationPoint_clear(cp); + UA_free(cp); + } + session->continuationPoints = NULL; + session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS; + + UA_Array_delete(session->params, session->paramsSize, + &UA_TYPES[UA_TYPES_KEYVALUEPAIR]); + session->params = NULL; + session->paramsSize = 0; +} + +void +UA_Session_attachToSecureChannel(UA_Session *session, UA_SecureChannel *channel) { + UA_Session_detachFromSecureChannel(session); + session->header.channel = channel; + SLIST_INSERT_HEAD(&channel->sessions, &session->header, next); +} + +void +UA_Session_detachFromSecureChannel(UA_Session *session) { + UA_SecureChannel *channel = session->header.channel; + if(!channel) + return; + session->header.channel = NULL; + UA_SessionHeader *sh; + SLIST_FOREACH(sh, &channel->sessions, next) { + if((UA_Session*)sh != session) + continue; + SLIST_REMOVE(&channel->sessions, sh, UA_SessionHeader, next); + break; + } +} + +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_clear(&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->policyContext, &session->serverNonce); +} + +void UA_Session_updateLifetime(UA_Session *session) { + session->validTill = UA_DateTime_nowMonotonic() + + (UA_DateTime)(session->timeout * UA_DATETIME_MSEC); +} + +#ifdef UA_ENABLE_SUBSCRIPTIONS + +void +UA_Session_attachSubscription(UA_Session *session, UA_Subscription *sub) { + /* Attach to the session */ + sub->session = session; + TAILQ_INSERT_TAIL(&session->subscriptions, sub, sessionListEntry); + + /* Increase the count */ + session->subscriptionsSize++; + + /* Increase the number of outstanding retransmissions */ + session->totalRetransmissionQueueSize += sub->retransmissionQueueSize; +} + +void +UA_Session_detachSubscription(UA_Server *server, UA_Session *session, + UA_Subscription *sub) { + /* Detach from the session */ + sub->session = NULL; + TAILQ_REMOVE(&session->subscriptions, sub, sessionListEntry); + + /* Reduce the count */ + UA_assert(session->subscriptionsSize > 0); + session->subscriptionsSize--; + + /* Reduce the number of outstanding retransmissions */ + session->totalRetransmissionQueueSize -= sub->retransmissionQueueSize; + + /* Send remaining publish responses if the last subscription was removed */ + if(!TAILQ_EMPTY(&session->subscriptions)) + return; + UA_PublishResponseEntry *pre; + while((pre = UA_Session_dequeuePublishReq(session))) { + UA_PublishResponse *response = &pre->response; + response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION; + response->responseHeader.timestamp = UA_DateTime_now(); + sendResponse(server, session, session->header.channel, pre->requestId, + (UA_Response*)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]); + UA_PublishResponse_clear(response); + UA_free(pre); + } +} + +UA_Subscription * +UA_Session_getSubscriptionById(UA_Session *session, UA_UInt32 subscriptionId) { + UA_Subscription *sub; + TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) { + /* Prevent lookup of subscriptions that are to be deleted with a statuschange */ + if(sub->statusChange != UA_STATUSCODE_GOOD) + continue; + if(sub->subscriptionId == subscriptionId) + break; + } + return sub; +} + +UA_Subscription * +UA_Server_getSubscriptionById(UA_Server *server, UA_UInt32 subscriptionId) { + UA_Subscription *sub; + LIST_FOREACH(sub, &server->subscriptions, serverListEntry) { + /* Prevent lookup of subscriptions that are to be deleted with a statuschange */ + if(sub->statusChange != UA_STATUSCODE_GOOD) + continue; + if(sub->subscriptionId == subscriptionId) + break; + } + 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 + +/* Session Handling */ + +UA_StatusCode +UA_Server_closeSession(UA_Server *server, const UA_NodeId *sessionId) { + UA_LOCK(&server->serviceMutex); + session_list_entry *entry; + UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID; + LIST_FOREACH(entry, &server->sessions, pointers) { + if(UA_NodeId_equal(&entry->session.sessionId, sessionId)) { + UA_Server_removeSession(server, entry, UA_DIAGNOSTICEVENT_CLOSE); + res = UA_STATUSCODE_GOOD; + break; + } + } + UA_UNLOCK(&server->serviceMutex); + return res; +} + +UA_StatusCode +UA_Server_setSessionParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name, const UA_Variant *parameter) { + UA_LOCK(&server->serviceMutex); + UA_Session *session = UA_Server_getSessionById(server, sessionId); + UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID; + if(session) + res = UA_KeyValueMap_set(&session->params, &session->paramsSize, + name, parameter); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +void +UA_Server_deleteSessionParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name) { + UA_LOCK(&server->serviceMutex); + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(session) + UA_KeyValueMap_delete(&session->params, &session->paramsSize, name); + UA_UNLOCK(&server->serviceMutex); +} + +UA_StatusCode +UA_Server_getSessionParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name, UA_Variant *outParameter) { + UA_LOCK(&server->serviceMutex); + if(!outParameter) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(!session) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADSESSIONIDINVALID; + } + + const UA_Variant *param = + UA_KeyValueMap_get(session->params, session->paramsSize, name); + if(!param) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADNOTFOUND; + } + + UA_StatusCode res = UA_Variant_copy(param, outParameter); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +UA_StatusCode +UA_Server_getSessionScalarParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name, const UA_DataType *type, + UA_Variant *outParameter) { + UA_LOCK(&server->serviceMutex); + if(!outParameter) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(!session) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADSESSIONIDINVALID; + } + + const UA_Variant *param = + UA_KeyValueMap_get(session->params, session->paramsSize, name); + if(!param || !UA_Variant_hasScalarType(param, type)) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADNOTFOUND; + } + + UA_StatusCode res = UA_Variant_copy(param, outParameter); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +UA_StatusCode +UA_Server_getSessionArrayParameter(UA_Server *server, const UA_NodeId *sessionId, + const char *name, const UA_DataType *type, + UA_Variant *outParameter) { + UA_LOCK(&server->serviceMutex); + if(!outParameter) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADINTERNALERROR; + } + + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(!session) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADSESSIONIDINVALID; + } + + const UA_Variant *param = + UA_KeyValueMap_get(session->params, session->paramsSize, name); + if(!param || !UA_Variant_hasArrayType(param, type)) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADNOTFOUND; + } + + UA_StatusCode res = UA_Variant_copy(param, outParameter); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +/**** amalgamated original file "/src/server/ua_nodes.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2015-2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2015-2016 (c) Sten Grüner + * Copyright 2015 (c) Chris Iatrou + * Copyright 2015, 2017 (c) Florian Palm + * Copyright 2015 (c) Oleksiy Vasylyev + * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Julian Grothoff + */ + + +/*****************/ +/* Node Pointers */ +/*****************/ + +#define UA_NODEPOINTER_MASK 0x03 +#define UA_NODEPOINTER_TAG_IMMEDIATE 0x00 +#define UA_NODEPOINTER_TAG_NODEID 0x01 +#define UA_NODEPOINTER_TAG_EXPANDEDNODEID 0x02 +#define UA_NODEPOINTER_TAG_NODE 0x03 + +void +UA_NodePointer_clear(UA_NodePointer *np) { + switch(np->immediate & UA_NODEPOINTER_MASK) { + case UA_NODEPOINTER_TAG_NODEID: + np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + UA_NodeId_delete((UA_NodeId*)(uintptr_t)np->id); + break; + case UA_NODEPOINTER_TAG_EXPANDEDNODEID: + np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + UA_ExpandedNodeId_delete((UA_ExpandedNodeId*)(uintptr_t) + np->expandedId); + break; + default: + break; + } + UA_NodePointer_init(np); +} + +UA_StatusCode +UA_NodePointer_copy(UA_NodePointer in, UA_NodePointer *out) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + UA_Byte tag = in.immediate & UA_NODEPOINTER_MASK; + in.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + switch(tag) { + case UA_NODEPOINTER_TAG_NODE: + in.id = &in.node->nodeId; + goto nodeid; /* fallthrough */ + case UA_NODEPOINTER_TAG_NODEID: + nodeid: + out->id = UA_NodeId_new(); + if(!out->id) + return UA_STATUSCODE_BADOUTOFMEMORY; + res = UA_NodeId_copy(in.id, (UA_NodeId*)(uintptr_t)out->id); + if(res != UA_STATUSCODE_GOOD) { + UA_free((void*)out->immediate); + out->immediate = 0; + break; + } + out->immediate |= UA_NODEPOINTER_TAG_NODEID; + break; + case UA_NODEPOINTER_TAG_EXPANDEDNODEID: + out->expandedId = UA_ExpandedNodeId_new(); + if(!out->expandedId) + return UA_STATUSCODE_BADOUTOFMEMORY; + res = UA_ExpandedNodeId_copy(in.expandedId, + (UA_ExpandedNodeId*)(uintptr_t) + out->expandedId); + if(res != UA_STATUSCODE_GOOD) { + UA_free((void*)out->immediate); + out->immediate = 0; + break; + } + out->immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID; + break; + default: + case UA_NODEPOINTER_TAG_IMMEDIATE: + *out = in; + break; + } + return res; +} + +UA_Boolean +UA_NodePointer_isLocal(UA_NodePointer np) { + UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK; + return (tag != UA_NODEPOINTER_TAG_EXPANDEDNODEID); +} + +UA_Order +UA_NodePointer_order(UA_NodePointer p1, UA_NodePointer p2) { + if(p1.immediate == p2.immediate) + return UA_ORDER_EQ; + + /* Extract the tag and resolve pointers to nodes */ + UA_Byte tag1 = p1.immediate & UA_NODEPOINTER_MASK; + if(tag1 == UA_NODEPOINTER_TAG_NODE) { + p1 = UA_NodePointer_fromNodeId(&p1.node->nodeId); + tag1 = p1.immediate & UA_NODEPOINTER_MASK; + } + UA_Byte tag2 = p2.immediate & UA_NODEPOINTER_MASK; + if(tag2 == UA_NODEPOINTER_TAG_NODE) { + p2 = UA_NodePointer_fromNodeId(&p2.node->nodeId); + tag2 = p2.immediate & UA_NODEPOINTER_MASK; + } + + /* Different tags, cannot be identical */ + if(tag1 != tag2) + return (tag1 > tag2) ? UA_ORDER_MORE : UA_ORDER_LESS; + + /* Immediate */ + if(UA_LIKELY(tag1 == UA_NODEPOINTER_TAG_IMMEDIATE)) + return (p1.immediate > p2.immediate) ? + UA_ORDER_MORE : UA_ORDER_LESS; + + /* Compare from pointers */ + p1.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + p2.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + if(tag1 == UA_NODEPOINTER_TAG_EXPANDEDNODEID) + return UA_ExpandedNodeId_order(p1.expandedId, p2.expandedId); + return UA_NodeId_order(p1.id, p2.id); +} + +UA_NodePointer +UA_NodePointer_fromNodeId(const UA_NodeId *id) { + UA_NodePointer np; + if(id->identifierType != UA_NODEIDTYPE_NUMERIC) { + np.id = id; + np.immediate |= UA_NODEPOINTER_TAG_NODEID; + return np; + } + +#if SIZE_MAX > UA_UINT32_MAX + /* 64bit: 4 Byte for the numeric identifier + 2 Byte for the namespaceIndex + * + 1 Byte for the tagging bit (zero) */ + np.immediate = ((uintptr_t)id->identifier.numeric) << 32; + np.immediate |= ((uintptr_t)id->namespaceIndex) << 8; +#else + /* 32bit: 3 Byte for the numeric identifier + 6 Bit for the namespaceIndex + * + 2 Bit for the tagging bit (zero) */ + if(id->namespaceIndex < (0x01 << 6) && + id->identifier.numeric < (0x01 << 24)) { + np.immediate = ((uintptr_t)id->identifier.numeric) << 8; + np.immediate |= ((uintptr_t)id->namespaceIndex) << 2; + } else { + np.id = id; + np.immediate |= UA_NODEPOINTER_TAG_NODEID; + } +#endif + return np; +} + +UA_NodeId +UA_NodePointer_toNodeId(UA_NodePointer np) { + UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK; + np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + switch(tag) { + case UA_NODEPOINTER_TAG_NODE: + return np.node->nodeId; + case UA_NODEPOINTER_TAG_NODEID: + return *np.id; + case UA_NODEPOINTER_TAG_EXPANDEDNODEID: + return np.expandedId->nodeId; + default: + case UA_NODEPOINTER_TAG_IMMEDIATE: + break; + } + + UA_NodeId id; + id.identifierType = UA_NODEIDTYPE_NUMERIC; +#if SIZE_MAX > UA_UINT32_MAX /* 64bit */ + id.namespaceIndex = (UA_UInt16)(np.immediate >> 8); + id.identifier.numeric = (UA_UInt32)(np.immediate >> 32); +#else /* 32bit */ + id.namespaceIndex = ((UA_Byte)np.immediate) >> 2; + id.identifier.numeric = np.immediate >> 8; +#endif + return id; +} + +UA_NodePointer +UA_NodePointer_fromExpandedNodeId(const UA_ExpandedNodeId *id) { + if(!UA_ExpandedNodeId_isLocal(id)) { + UA_NodePointer np; + np.expandedId = id; + np.immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID; + return np; + } + return UA_NodePointer_fromNodeId(&id->nodeId); +} + +UA_ExpandedNodeId +UA_NodePointer_toExpandedNodeId(UA_NodePointer np) { + /* Resolve node pointer to get the NodeId */ + UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK; + if(tag == UA_NODEPOINTER_TAG_NODE) { + np = UA_NodePointer_fromNodeId(&np.node->nodeId); + tag = np.immediate & UA_NODEPOINTER_MASK; + } + + /* ExpandedNodeId, make a shallow copy */ + if(tag == UA_NODEPOINTER_TAG_EXPANDEDNODEID) { + np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK; + return *np.expandedId; + } + + /* NodeId, either immediate or via a pointer */ + UA_ExpandedNodeId en; + UA_ExpandedNodeId_init(&en); + en.nodeId = UA_NodePointer_toNodeId(np); + return en; +} + +/**************/ +/* References */ +/**************/ + +static UA_StatusCode +addReferenceTarget(UA_NodeReferenceKind *refs, UA_NodePointer target, + UA_UInt32 targetNameHash); + +static enum aa_cmp +cmpRefTargetId(const void *a, const void *b) { + const UA_ReferenceTargetTreeElem *aa = (const UA_ReferenceTargetTreeElem*)a; + const UA_ReferenceTargetTreeElem *bb = (const UA_ReferenceTargetTreeElem*)b; + if(aa->targetIdHash < bb->targetIdHash) + return AA_CMP_LESS; + if(aa->targetIdHash > bb->targetIdHash) + return AA_CMP_MORE; + return (enum aa_cmp)UA_NodePointer_order(aa->target.targetId, + bb->target.targetId); +} + +static enum aa_cmp +cmpRefTargetName(const void *a, const void *b) { + const UA_UInt32 *nameHashA = (const UA_UInt32*)a; + const UA_UInt32 *nameHashB = (const UA_UInt32*)b; + if(*nameHashA < *nameHashB) + return AA_CMP_LESS; + if(*nameHashA > *nameHashB) + return AA_CMP_MORE; + return AA_CMP_EQ; +} + +/* Reusable binary search tree "heads". Just switch out the root pointer. */ +static const struct aa_head refIdTree = + { NULL, cmpRefTargetId, offsetof(UA_ReferenceTargetTreeElem, idTreeEntry), 0 }; +const struct aa_head refNameTree = + { NULL, cmpRefTargetName, offsetof(UA_ReferenceTargetTreeElem, nameTreeEntry), + offsetof(UA_ReferenceTarget, targetNameHash) }; + +const UA_ReferenceTarget * +UA_NodeReferenceKind_iterate(const UA_NodeReferenceKind *rk, + const UA_ReferenceTarget *prev) { + /* Return from the tree */ + if(rk->hasRefTree) { + const struct aa_head _refIdTree = + { rk->targets.tree.idTreeRoot, cmpRefTargetId, + offsetof(UA_ReferenceTargetTreeElem, idTreeEntry), 0 }; + if(prev == NULL) + return (const UA_ReferenceTarget*)aa_min(&_refIdTree); + return (const UA_ReferenceTarget*)aa_next(&_refIdTree, prev); + } + if(prev == NULL) /* Return start of the array */ + return rk->targets.array; + if(prev + 1 >= &rk->targets.array[rk->targetsSize]) + return NULL; /* End of the array */ + return prev + 1; /* Next element in the array */ +} + +/* Also deletes the elements of the tree */ +static void +moveTreeToArray(UA_ReferenceTarget *array, size_t *pos, + struct aa_entry *entry) { + if(!entry) + return; + UA_ReferenceTargetTreeElem *elem = (UA_ReferenceTargetTreeElem*) + ((uintptr_t)entry - offsetof(UA_ReferenceTargetTreeElem, idTreeEntry)); + moveTreeToArray(array, pos, elem->idTreeEntry.left); + moveTreeToArray(array, pos, elem->idTreeEntry.right); + array[*pos] = elem->target; + (*pos)++; + UA_free(elem); +} + +UA_StatusCode +UA_NodeReferenceKind_switch(UA_NodeReferenceKind *rk) { + if(rk->hasRefTree) { + /* From tree to array */ + UA_ReferenceTarget *array = (UA_ReferenceTarget*) + UA_malloc(sizeof(UA_ReferenceTarget) * rk->targetsSize); + if(!array) + return UA_STATUSCODE_BADOUTOFMEMORY; + size_t pos = 0; + moveTreeToArray(array, &pos, rk->targets.tree.idTreeRoot); + rk->targets.array = array; + rk->hasRefTree = false; + return UA_STATUSCODE_GOOD; + } + + /* From array to tree */ + UA_NodeReferenceKind newRk = *rk; + newRk.hasRefTree = true; + newRk.targets.tree.idTreeRoot = NULL; + newRk.targets.tree.nameTreeRoot = NULL; + for(size_t i = 0; i < rk->targetsSize; i++) { + UA_StatusCode res = + addReferenceTarget(&newRk, rk->targets.array[i].targetId, + rk->targets.array[i].targetNameHash); + if(res != UA_STATUSCODE_GOOD) { + struct aa_head _refIdTree = refIdTree; + _refIdTree.root = newRk.targets.tree.idTreeRoot; + while(_refIdTree.root) { + UA_ReferenceTargetTreeElem *elem = (UA_ReferenceTargetTreeElem*) + ((uintptr_t)_refIdTree.root - + offsetof(UA_ReferenceTargetTreeElem, idTreeEntry)); + aa_remove(&_refIdTree, elem); + UA_NodePointer_clear(&elem->target.targetId); + UA_free(elem); + } + return res; + } + } + for(size_t i = 0; i < rk->targetsSize; i++) + UA_NodePointer_clear(&rk->targets.array[i].targetId); + UA_free(rk->targets.array); + *rk = newRk; + return UA_STATUSCODE_GOOD; +} + +const UA_ReferenceTarget * +UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk, + const UA_ExpandedNodeId *targetId) { + UA_NodePointer targetP = UA_NodePointer_fromExpandedNodeId(targetId); + + /* Return from the tree */ + if(rk->hasRefTree) { + UA_ReferenceTargetTreeElem tmpTarget; + tmpTarget.target.targetId = targetP; + tmpTarget.targetIdHash = UA_ExpandedNodeId_hash(targetId); + const struct aa_head _refIdTree = + { rk->targets.tree.idTreeRoot, cmpRefTargetId, + offsetof(UA_ReferenceTargetTreeElem, idTreeEntry), 0 }; + return (const UA_ReferenceTarget*)aa_find(&_refIdTree, &tmpTarget); + } + + /* Return from the array */ + for(size_t i = 0; i < rk->targetsSize; i++) { + if(UA_NodePointer_equal(targetP, rk->targets.array[i].targetId)) + return &rk->targets.array[i]; + } + return NULL; +} + +const UA_Node * +UA_NODESTORE_GETFROMREF(UA_Server *server, UA_NodePointer target) { + if(!UA_NodePointer_isLocal(target)) + return NULL; + UA_NodeId id = UA_NodePointer_toNodeId(target); + return UA_NODESTORE_GET(server, &id); +} + +/* General node handling methods. There is no UA_Node_new() method here. + * Creating nodes is part of the Nodestore layer */ + +void UA_Node_clear(UA_Node *node) { + /* Delete references */ + UA_Node_deleteReferences(node); + + /* Delete other head content */ + UA_NodeHead *head = &node->head; + UA_NodeId_clear(&head->nodeId); + UA_QualifiedName_clear(&head->browseName); + UA_LocalizedText_clear(&head->displayName); + UA_LocalizedText_clear(&head->description); + + /* Delete unique content of the nodeclass */ + switch(head->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 = &node->variableNode; + UA_NodeId_clear(&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_clear(&p->value.data.value); + break; + } + case UA_NODECLASS_REFERENCETYPE: { + UA_ReferenceTypeNode *p = &node->referenceTypeNode; + UA_LocalizedText_clear(&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) { + dst->accessLevel = src->accessLevel; + dst->minimumSamplingInterval = src->minimumSamplingInterval; + dst->historizing = src->historizing; + dst->isDynamic = src->isDynamic; + return UA_CommonVariableNode_copy(src, dst); +} + +static UA_StatusCode +UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, + UA_VariableTypeNode *dst) { + dst->isAbstract = src->isAbstract; + return UA_CommonVariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst); +} + +static UA_StatusCode +UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) { + dst->executable = src->executable; + dst->method = src->method; +#if UA_MULTITHREADING >= 100 + dst->async = src->async; +#endif + 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) { + dst->isAbstract = src->isAbstract; + dst->symmetric = src->symmetric; + dst->referenceTypeIndex = src->referenceTypeIndex; + dst->subTypes = src->subTypes; + return UA_LocalizedText_copy(&src->inverseName, &dst->inverseName); +} + +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) { + const UA_NodeHead *srchead = &src->head; + UA_NodeHead *dsthead = &dst->head; + if(srchead->nodeClass != dsthead->nodeClass) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Copy standard content */ + UA_StatusCode retval = UA_NodeId_copy(&srchead->nodeId, &dsthead->nodeId); + retval |= UA_QualifiedName_copy(&srchead->browseName, &dsthead->browseName); + retval |= UA_LocalizedText_copy(&srchead->displayName, &dsthead->displayName); + retval |= UA_LocalizedText_copy(&srchead->description, &dsthead->description); + dsthead->writeMask = srchead->writeMask; + dsthead->context = srchead->context; + dsthead->constructed = srchead->constructed; +#ifdef UA_ENABLE_SUBSCRIPTIONS + dsthead->monitoredItems = srchead->monitoredItems; +#endif + if(retval != UA_STATUSCODE_GOOD) { + UA_Node_clear(dst); + return retval; + } + + /* Copy the references */ + dsthead->references = NULL; + if(srchead->referencesSize > 0) { + dsthead->references = (UA_NodeReferenceKind*) + UA_calloc(srchead->referencesSize, sizeof(UA_NodeReferenceKind)); + if(!dsthead->references) { + UA_Node_clear(dst); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + dsthead->referencesSize = srchead->referencesSize; + + for(size_t i = 0; i < srchead->referencesSize; ++i) { + UA_NodeReferenceKind *srefs = &srchead->references[i]; + UA_NodeReferenceKind *drefs = &dsthead->references[i]; + drefs->referenceTypeIndex = srefs->referenceTypeIndex; + drefs->isInverse = srefs->isInverse; + drefs->hasRefTree = srefs->hasRefTree; /* initially empty */ + + /* Copy all the targets */ + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(srefs, t))) { + retval = addReferenceTarget(drefs, t->targetId, t->targetNameHash); + if(retval != UA_STATUSCODE_GOOD) { + UA_Node_clear(dst); + return retval; + } + } + } + } + + /* Copy unique content of the nodeclass */ + switch(src->head.nodeClass) { + case UA_NODECLASS_OBJECT: + retval = UA_ObjectNode_copy(&src->objectNode, &dst->objectNode); + break; + case UA_NODECLASS_VARIABLE: + retval = UA_VariableNode_copy(&src->variableNode, &dst->variableNode); + break; + case UA_NODECLASS_METHOD: + retval = UA_MethodNode_copy(&src->methodNode, &dst->methodNode); + break; + case UA_NODECLASS_OBJECTTYPE: + retval = UA_ObjectTypeNode_copy(&src->objectTypeNode, &dst->objectTypeNode); + break; + case UA_NODECLASS_VARIABLETYPE: + retval = UA_VariableTypeNode_copy(&src->variableTypeNode, &dst->variableTypeNode); + break; + case UA_NODECLASS_REFERENCETYPE: + retval = UA_ReferenceTypeNode_copy(&src->referenceTypeNode, &dst->referenceTypeNode); + break; + case UA_NODECLASS_DATATYPE: + retval = UA_DataTypeNode_copy(&src->dataTypeNode, &dst->dataTypeNode); + break; + case UA_NODECLASS_VIEW: + retval = UA_ViewNode_copy(&src->viewNode, &dst->viewNode); + break; + default: + break; + } + + if(retval != UA_STATUSCODE_GOOD) + UA_Node_clear(dst); + + return retval; +} + +UA_Node * +UA_Node_copy_alloc(const UA_Node *src) { + size_t nodesize = 0; + switch(src->head.nodeClass) { + case UA_NODECLASS_OBJECT: + nodesize = sizeof(UA_ObjectNode); + break; + case UA_NODECLASS_VARIABLE: + nodesize = sizeof(UA_VariableNode); + break; + case UA_NODECLASS_METHOD: + nodesize = sizeof(UA_MethodNode); + break; + case UA_NODECLASS_OBJECTTYPE: + nodesize = sizeof(UA_ObjectTypeNode); + break; + case UA_NODECLASS_VARIABLETYPE: + nodesize = sizeof(UA_VariableTypeNode); + break; + case UA_NODECLASS_REFERENCETYPE: + nodesize = sizeof(UA_ReferenceTypeNode); + break; + case UA_NODECLASS_DATATYPE: + nodesize = sizeof(UA_DataTypeNode); + break; + case UA_NODECLASS_VIEW: + nodesize = sizeof(UA_ViewNode); + break; + default: + return NULL; + } + + UA_Node *dst = (UA_Node*)UA_calloc(1, nodesize); + if(!dst) + return NULL; + + dst->head.nodeClass = src->head.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_NodeHead *head, const UA_NodeAttributes *attr) { + /* UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId); */ + /* UA_QualifiedName_copy(&item->browseName, &node->browseName); */ + + head->writeMask = attr->writeMask; + UA_StatusCode retval = UA_LocalizedText_copy(&attr->description, &head->description); + /* The new nodeset format has optional display names: + * https://github.com/open62541/open62541/issues/2627. If the display name + * is NULL, take the name part of the browse name */ + if(attr->displayName.text.length == 0) + retval |= UA_String_copy(&head->browseName.name, &head->displayName.text); + else + retval |= UA_LocalizedText_copy(&attr->displayName, &head->displayName); + return retval; +} + +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); + if(retval != UA_STATUSCODE_GOOD) + return retval; + node->valueRank = attr->valueRank; + + /* Copy the value */ + retval = UA_Variant_copy(&attr->value, &node->value.data.value.value); + node->valueSource = UA_VALUESOURCE_DATA; + node->value.data.value.hasValue = (node->value.data.value.value.type != NULL); + + 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->head.nodeClass) { + case UA_NODECLASS_OBJECT: + CHECK_ATTRIBUTES(OBJECTATTRIBUTES); + retval = copyObjectNodeAttributes(&node->objectNode, + (const UA_ObjectAttributes*)attributes); + break; + case UA_NODECLASS_VARIABLE: + CHECK_ATTRIBUTES(VARIABLEATTRIBUTES); + retval = copyVariableNodeAttributes(&node->variableNode, + (const UA_VariableAttributes*)attributes); + break; + case UA_NODECLASS_OBJECTTYPE: + CHECK_ATTRIBUTES(OBJECTTYPEATTRIBUTES); + retval = copyObjectTypeNodeAttributes(&node->objectTypeNode, + (const UA_ObjectTypeAttributes*)attributes); + break; + case UA_NODECLASS_VARIABLETYPE: + CHECK_ATTRIBUTES(VARIABLETYPEATTRIBUTES); + retval = copyVariableTypeNodeAttributes(&node->variableTypeNode, + (const UA_VariableTypeAttributes*)attributes); + break; + case UA_NODECLASS_REFERENCETYPE: + CHECK_ATTRIBUTES(REFERENCETYPEATTRIBUTES); + retval = copyReferenceTypeNodeAttributes(&node->referenceTypeNode, + (const UA_ReferenceTypeAttributes*)attributes); + break; + case UA_NODECLASS_DATATYPE: + CHECK_ATTRIBUTES(DATATYPEATTRIBUTES); + retval = copyDataTypeNodeAttributes(&node->dataTypeNode, + (const UA_DataTypeAttributes*)attributes); + break; + case UA_NODECLASS_VIEW: + CHECK_ATTRIBUTES(VIEWATTRIBUTES); + retval = copyViewNodeAttributes(&node->viewNode, (const UA_ViewAttributes*)attributes); + break; + case UA_NODECLASS_METHOD: + CHECK_ATTRIBUTES(METHODATTRIBUTES); + retval = copyMethodNodeAttributes(&node->methodNode, (const UA_MethodAttributes*)attributes); + break; + case UA_NODECLASS_UNSPECIFIED: + default: + retval = UA_STATUSCODE_BADNODECLASSINVALID; + } + + if(retval == UA_STATUSCODE_GOOD) + retval = copyStandardAttributes(&node->head, (const UA_NodeAttributes*)attributes); + if(retval != UA_STATUSCODE_GOOD) + UA_Node_clear(node); + return retval; +} + +/*********************/ +/* Manage References */ +/*********************/ + +static UA_StatusCode +addReferenceTarget(UA_NodeReferenceKind *rk, UA_NodePointer targetId, + UA_UInt32 targetNameHash) { + /* Insert into array */ + if(!rk->hasRefTree) { + UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*) + UA_realloc(rk->targets.array, + sizeof(UA_ReferenceTarget) * (rk->targetsSize + 1)); + if(!newRefs) + return UA_STATUSCODE_BADOUTOFMEMORY; + rk->targets.array = newRefs; + + UA_StatusCode retval = + UA_NodePointer_copy(targetId, + &rk->targets.array[rk->targetsSize].targetId); + rk->targets.array[rk->targetsSize].targetNameHash = targetNameHash; + if(retval != UA_STATUSCODE_GOOD) { + if(rk->targetsSize == 0) { + UA_free(rk->targets.array); + rk->targets.array = NULL; + } + return retval; + } + rk->targetsSize++; + return UA_STATUSCODE_GOOD; + } + + /* Insert into tree */ + UA_ReferenceTargetTreeElem *entry = (UA_ReferenceTargetTreeElem*) + UA_malloc(sizeof(UA_ReferenceTargetTreeElem)); + if(!entry) + return UA_STATUSCODE_BADOUTOFMEMORY; + + UA_StatusCode retval = + UA_NodePointer_copy(targetId, &entry->target.targetId); + if(retval != UA_STATUSCODE_GOOD) { + UA_free(entry); + return retval; + } + + /* <-- The point of no return --> */ + + UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(targetId); + entry->targetIdHash = UA_ExpandedNodeId_hash(&en); + entry->target.targetNameHash = targetNameHash; + + /* Insert to the id lookup binary search tree. Only the root is kept in refs + * to save space. */ + struct aa_head _refIdTree = refIdTree; + _refIdTree.root = rk->targets.tree.idTreeRoot; + aa_insert(&_refIdTree, entry); + rk->targets.tree.idTreeRoot = _refIdTree.root; + + /* Insert to the name lookup binary search tree */ + struct aa_head _refNameTree = refNameTree; + _refNameTree.root = rk->targets.tree.nameTreeRoot; + aa_insert(&_refNameTree, entry); + rk->targets.tree.nameTreeRoot = _refNameTree.root; + + rk->targetsSize++; + + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +addReferenceKind(UA_NodeHead *head, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_NodePointer target, UA_UInt32 targetBrowseNameHash) { + UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*) + UA_realloc(head->references, + sizeof(UA_NodeReferenceKind) * (head->referencesSize+1)); + if(!refs) + return UA_STATUSCODE_BADOUTOFMEMORY; + head->references = refs; + + UA_NodeReferenceKind *newRef = &refs[head->referencesSize]; + memset(newRef, 0, sizeof(UA_NodeReferenceKind)); + newRef->referenceTypeIndex = refTypeIndex; + newRef->isInverse = !isForward; + UA_StatusCode retval = + addReferenceTarget(newRef, target, targetBrowseNameHash); + if(retval != UA_STATUSCODE_GOOD) { + if(head->referencesSize == 0) { + UA_free(head->references); + head->references = NULL; + } + return retval; + } + + head->referencesSize++; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Node_addReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_ExpandedNodeId *targetNodeId, + UA_UInt32 targetBrowseNameHash) { + /* Find the matching reference kind */ + for(size_t i = 0; i < node->head.referencesSize; ++i) { + UA_NodeReferenceKind *refs = &node->head.references[i]; + + /* Reference direction does not match */ + if(refs->isInverse == isForward) + continue; + + /* Reference type does not match */ + if(refs->referenceTypeIndex != refTypeIndex) + continue; + + /* Does an identical reference already exist? */ + const UA_ReferenceTarget *found = + UA_NodeReferenceKind_findTarget(refs, targetNodeId); + if(found) + return UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED; + + /* Add to existing ReferenceKind */ + return addReferenceTarget(refs, UA_NodePointer_fromExpandedNodeId(targetNodeId), + targetBrowseNameHash); + } + + /* Add new ReferenceKind for the target */ + return addReferenceKind(&node->head, refTypeIndex, isForward, + UA_NodePointer_fromExpandedNodeId(targetNodeId), + targetBrowseNameHash); + +} + +UA_StatusCode +UA_Node_deleteReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward, + const UA_ExpandedNodeId *targetNodeId) { + struct aa_head _refIdTree = refIdTree; + struct aa_head _refNameTree = refNameTree; + + UA_NodeHead *head = &node->head; + for(size_t i = 0; i < head->referencesSize; i++) { + UA_NodeReferenceKind *refs = &head->references[i]; + if(isForward == refs->isInverse) + continue; + if(refTypeIndex != refs->referenceTypeIndex) + continue; + + /* Cast out the const qualifier (hack!) */ + UA_ReferenceTarget *target = (UA_ReferenceTarget*)(uintptr_t) + UA_NodeReferenceKind_findTarget(refs, targetNodeId); + if(!target) + continue; + + /* Ok, delete the reference. Cannot fail */ + refs->targetsSize--; + + if(!refs->hasRefTree) { + /* Remove from array */ + UA_NodePointer_clear(&target->targetId); + + /* Elements remaining. Realloc. */ + if(refs->targetsSize > 0) { + if(target != &refs->targets.array[refs->targetsSize]) + *target = refs->targets.array[refs->targetsSize]; + UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*) + UA_realloc(refs->targets.array, + sizeof(UA_ReferenceTarget) * refs->targetsSize); + if(newRefs) + refs->targets.array = newRefs; + return UA_STATUSCODE_GOOD; /* Realloc allowed to fail */ + } + + /* Remove the last target. Remove the ReferenceKind below */ + UA_free(refs->targets.array); + } else { + /* Remove from the tree */ + _refIdTree.root = refs->targets.tree.idTreeRoot; + aa_remove(&_refIdTree, target); + refs->targets.tree.idTreeRoot = _refIdTree.root; + + _refNameTree.root = refs->targets.tree.nameTreeRoot; + aa_remove(&_refNameTree, target); + refs->targets.tree.nameTreeRoot = _refNameTree.root; + + UA_NodePointer_clear(&target->targetId); + UA_free(target); + if(refs->targets.tree.idTreeRoot) + return UA_STATUSCODE_GOOD; /* At least one target remains */ + } + + /* No targets remaining. Remove the ReferenceKind. */ + head->referencesSize--; + if(head->referencesSize > 0) { + /* No target for the ReferenceType remaining. Remove and shrink down + * allocated buffer. Ignore errors in case memory buffer could not + * be shrinked down. */ + if(i != head->referencesSize) + head->references[i] = head->references[node->head.referencesSize]; + UA_NodeReferenceKind *newRefs = (UA_NodeReferenceKind*) + UA_realloc(head->references, + sizeof(UA_NodeReferenceKind) * head->referencesSize); + if(newRefs) + head->references = newRefs; + } else { + /* No remaining references of any ReferenceType */ + UA_free(head->references); + head->references = NULL; + } + return UA_STATUSCODE_GOOD; + } + return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED; +} + +void +UA_Node_deleteReferencesSubset(UA_Node *node, const UA_ReferenceTypeSet *keepSet) { + UA_NodeHead *head = &node->head; + struct aa_head _refIdTree = refIdTree; + for(size_t i = 0; i < head->referencesSize; i++) { + /* Keep the references of this type? */ + UA_NodeReferenceKind *refs = &head->references[i]; + if(UA_ReferenceTypeSet_contains(keepSet, refs->referenceTypeIndex)) + continue; + + /* Remove all target entries. Don't remove entries from browseName tree. + * The entire ReferenceKind will be removed anyway. */ + if(!refs->hasRefTree) { + for(size_t j = 0; j < refs->targetsSize; j++) + UA_NodePointer_clear(&refs->targets.array[j].targetId); + UA_free(refs->targets.array); + } else { + _refIdTree.root = refs->targets.tree.idTreeRoot; + while(_refIdTree.root) { + UA_ReferenceTargetTreeElem *elem = (UA_ReferenceTargetTreeElem*) + ((uintptr_t)_refIdTree.root - + offsetof(UA_ReferenceTargetTreeElem, idTreeEntry)); + aa_remove(&_refIdTree, elem); + UA_NodePointer_clear(&elem->target.targetId); + UA_free(elem); + } + } + + /* Move last references-kind entry to this position. Don't memcpy over + * the same position. Decrease i to repeat at this location. */ + head->referencesSize--; + if(i != head->referencesSize) { + head->references[i] = head->references[head->referencesSize]; + i--; + } + } + + if(head->referencesSize > 0) { + /* Realloc to save memory. Ignore if realloc fails. */ + UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*) + UA_realloc(head->references, + sizeof(UA_NodeReferenceKind) * head->referencesSize); + if(refs) + head->references = refs; + } else { + /* The array is empty. Remove. */ + UA_free(head->references); + head->references = NULL; + } +} + +void UA_Node_deleteReferences(UA_Node *node) { + UA_ReferenceTypeSet noRefs; + UA_ReferenceTypeSet_init(&noRefs); + UA_Node_deleteReferencesSubset(node, &noRefs); +} + +/**** amalgamated original file "/src/server/ua_server.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + * Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang) + * Copyright 2019 (c) Kalycito Infotech Private Limited + * Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes) + */ + + +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL +#endif + + +#ifdef UA_ENABLE_SUBSCRIPTIONS +#endif + +#ifdef UA_ENABLE_VALGRIND_INTERACTIVE +#include +#endif + +#define STARTCHANNELID 1 +#define STARTTOKENID 1 + +/**********************/ +/* Namespace Handling */ +/**********************/ + +/* The NS1 Uri can be changed by the user to some custom string. This method is + * called to initialize the NS1 Uri if it is not set before to the default + * Application URI. + * + * This is done as soon as the Namespace Array is read or written via node value + * read / write services, or UA_Server_addNamespace, + * UA_Server_getNamespaceByName or UA_Server_run_startup is called. + * + * Therefore one has to set the custom NS1 URI before one of the previously + * mentioned steps. */ +void +setupNs1Uri(UA_Server *server) { + if(!server->namespaces[1].data) { + UA_String_copy(&server->config.applicationDescription.applicationUri, + &server->namespaces[1]); + } +} + +UA_UInt16 addNamespace(UA_Server *server, const UA_String name) { + /* ensure that the uri for ns1 is set up from the app description */ + setupNs1Uri(server); + + /* 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)); + UA_CHECK_MEM(newNS, return 0); + + server->namespaces = newNS; + + /* Copy the namespace string */ + UA_StatusCode retval = UA_String_copy(&name, &server->namespaces[server->namespacesSize]); + UA_CHECK_STATUS(retval, 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; + UA_LOCK(&server->serviceMutex); + UA_UInt16 retVal = addNamespace(server, nameString); + UA_UNLOCK(&server->serviceMutex); + return retVal; +} + +UA_ServerConfig* +UA_Server_getConfig(UA_Server *server) { + UA_CHECK_MEM(server, return NULL); + return &server->config; +} + +UA_StatusCode +getNamespaceByName(UA_Server *server, const UA_String namespaceUri, + size_t *foundIndex) { + /* ensure that the uri for ns1 is set up from the app description */ + setupNs1Uri(server); + UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND; + for(size_t idx = 0; idx < server->namespacesSize; idx++) { + if(UA_String_equal(&server->namespaces[idx], &namespaceUri)) { + (*foundIndex) = idx; + res = UA_STATUSCODE_GOOD; + break; + } + } + return res; +} + +UA_StatusCode +UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri, + size_t *foundIndex) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode res = getNamespaceByName(server, namespaceUri, foundIndex); + UA_UNLOCK(&server->serviceMutex); + return res; +} + +UA_StatusCode +UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId, + UA_NodeIteratorCallback callback, void *handle) { + UA_BrowseDescription bd; + UA_BrowseDescription_init(&bd); + bd.nodeId = parentNodeId; + bd.browseDirection = UA_BROWSEDIRECTION_BOTH; + bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_ISFORWARD; + + UA_BrowseResult br = UA_Server_browse(server, 0, &bd); + UA_StatusCode res = br.statusCode; + UA_CHECK_STATUS(res, goto cleanup); + + for(size_t i = 0; i < br.referencesSize; i++) { + if(!UA_ExpandedNodeId_isLocal(&br.references[i].nodeId)) + continue; + res = callback(br.references[i].nodeId.nodeId, !br.references[i].isForward, + br.references[i].referenceTypeId, handle); + UA_CHECK_STATUS(res, goto cleanup); + } +cleanup: + UA_BrowseResult_clear(&br); + return res; +} + +/********************/ +/* Server Lifecycle */ +/********************/ + +static void +serverExecuteRepeatedCallback(UA_Server *server, UA_ApplicationCallback cb, + void *callbackApplication, void *data); + +/* The server needs to be stopped before it can be deleted */ +void UA_Server_delete(UA_Server *server) { + UA_LOCK(&server->serviceMutex); + + UA_Server_deleteSecureChannels(server); + session_list_entry *current, *temp; + LIST_FOREACH_SAFE(current, &server->sessions, pointers, temp) { + UA_Server_removeSession(server, current, UA_DIAGNOSTICEVENT_CLOSE); + } + UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]); + +#ifdef UA_ENABLE_SUBSCRIPTIONS + UA_MonitoredItem *mon, *mon_tmp; + LIST_FOREACH_SAFE(mon, &server->localMonitoredItems, listEntry, mon_tmp) { + LIST_REMOVE(mon, listEntry); + UA_MonitoredItem_delete(server, mon); + } + + /* Remove subscriptions without a session */ + UA_Subscription *sub, *sub_tmp; + LIST_FOREACH_SAFE(sub, &server->subscriptions, serverListEntry, sub_tmp) { + UA_Subscription_delete(server, sub); + } + UA_assert(server->monitoredItemsSize == 0); + UA_assert(server->subscriptionsSize == 0); + +#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS + UA_ConditionList_delete(server); +#endif + +#endif + +#ifdef UA_ENABLE_PUBSUB + UA_PubSubManager_delete(server, &server->pubSubManager); +#endif + +#ifdef UA_ENABLE_DISCOVERY + UA_DiscoveryManager_clear(&server->discoveryManager, server); +#endif + +#if UA_MULTITHREADING >= 100 + UA_AsyncManager_clear(&server->asyncManager, server); +#endif + + /* Clean up the Admin Session */ + UA_Session_clear(&server->adminSession, server); + + UA_UNLOCK(&server->serviceMutex); /* The timer has its own mutex */ + + /* Execute all remaining delayed events and clean up the timer */ + UA_Timer_process(&server->timer, UA_DateTime_nowMonotonic() + 1, + (UA_TimerExecutionCallback)serverExecuteRepeatedCallback, server); + UA_Timer_clear(&server->timer); + + /* Clean up the config */ + UA_ServerConfig_clean(&server->config); + +#if UA_MULTITHREADING >= 100 + UA_LOCK_DESTROY(&server->networkMutex); + UA_LOCK_DESTROY(&server->serviceMutex); +#endif + + /* 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_LOCK(&server->serviceMutex); + UA_DateTime nowMonotonic = UA_DateTime_nowMonotonic(); + UA_Server_cleanupSessions(server, nowMonotonic); + UA_Server_cleanupTimedOutSecureChannels(server, nowMonotonic); +#ifdef UA_ENABLE_DISCOVERY + UA_Discovery_cleanupTimedOut(server, nowMonotonic); +#endif + UA_UNLOCK(&server->serviceMutex); +} + +/********************/ +/* Server Lifecycle */ +/********************/ + +static +UA_INLINE +UA_Boolean UA_Server_NodestoreIsConfigured(UA_Server *server) { + return server->config.nodestore.getNode != NULL; +} + +static UA_Server * +UA_Server_init(UA_Server *server) { + + UA_StatusCode res = UA_STATUSCODE_GOOD; + UA_CHECK_FATAL(UA_Server_NodestoreIsConfigured(server), goto cleanup, + &server->config.logger, UA_LOGCATEGORY_SERVER, + "No Nodestore configured in the server" + ); + + /* Init start time to zero, the actual start time will be sampled in + * UA_Server_run_startup() */ + server->startTime = 0; + + /* Set a seed for non-cyptographic randomness */ +#ifndef UA_ENABLE_DETERMINISTIC_RNG + UA_random_seed((UA_UInt64)UA_DateTime_now()); +#endif + +#if UA_MULTITHREADING >= 100 + UA_LOCK_INIT(&server->networkMutex); + UA_LOCK_INIT(&server->serviceMutex); +#endif + + /* Initialize the handling of repeated callbacks */ + UA_Timer_init(&server->timer); + + /* Initialize the adminSession */ + UA_Session_init(&server->adminSession); + server->adminSession.sessionId.identifierType = UA_NODEIDTYPE_GUID; + server->adminSession.sessionId.identifier.guid.data1 = 1; + server->adminSession.validTill = UA_INT64_MAX; + + /* Create Namespaces 0 and 1 + * Ns1 will be filled later with the uri from the app description */ + server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]); + UA_CHECK_MEM(server->namespaces, goto cleanup); + + server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/"); + server->namespaces[1] = UA_STRING_NULL; + server->namespacesSize = 2; + + /* Initialize SecureChannel */ + TAILQ_INIT(&server->channels); + /* TODO: use an ID that is likely to be unique after a restart */ + server->lastChannelId = STARTCHANNELID; + server->lastTokenId = STARTTOKENID; + + /* Initialize Session Management */ + LIST_INIT(&server->sessions); + server->sessionCount = 0; + +#if UA_MULTITHREADING >= 100 + UA_AsyncManager_init(&server->asyncManager, server); +#endif + + /* Add a regular callback for cleanup and maintenance. With a 10s interval. */ + UA_Server_addRepeatedCallback(server, (UA_ServerCallback)UA_Server_cleanup, NULL, + 10000.0, NULL); + + /* Initialize namespace 0*/ + res = UA_Server_initNS0(server); + UA_CHECK_STATUS(res, goto cleanup); + +#ifdef UA_ENABLE_PUBSUB + /* Build PubSub information model */ +#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL + UA_Server_initPubSubNS0(server); +#endif + +#ifdef UA_ENABLE_PUBSUB_MONITORING + /* setup default PubSub monitoring callbacks */ + res = UA_PubSubManager_setDefaultMonitoringCallbacks(&server->config.pubSubConfig.monitoringInterface); + UA_CHECK_STATUS(res, goto cleanup); +#endif /* UA_ENABLE_PUBSUB_MONITORING */ +#endif /* UA_ENABLE_PUBSUB */ + return server; + + cleanup: + UA_Server_delete(server); + return NULL; +} + +UA_Server * +UA_Server_newWithConfig(UA_ServerConfig *config) { + UA_CHECK_MEM(config, return NULL); + + UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server)); + UA_CHECK_MEM(server, UA_ServerConfig_clean(config); return NULL); + + server->config = *config; + /* The config might have been "moved" into the server struct. Ensure that + * the logger pointer is correct. */ + for(size_t i = 0; i < server->config.securityPoliciesSize; i++) + server->config.securityPolicies[i].logger = &server->config.logger; + + /* Reset the old config */ + memset(config, 0, sizeof(UA_ServerConfig)); + return UA_Server_init(server); +} + +/* Returns if the server should be shut down immediately */ +static UA_Boolean +setServerShutdown(UA_Server *server) { + if(server->endTime != 0) + return false; + if(server->config.shutdownDelay == 0) + return true; + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Shutting down the server with a delay of %i ms", (int)server->config.shutdownDelay); + server->endTime = UA_DateTime_now() + (UA_DateTime)(server->config.shutdownDelay * UA_DATETIME_MSEC); + return false; +} + +/*******************/ +/* Timed Callbacks */ +/*******************/ + +UA_StatusCode +UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_DateTime date, UA_UInt64 *callbackId) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = + UA_Timer_addTimedCallback(&server->timer, + (UA_ApplicationCallback)callback, + server, data, date, callbackId); + UA_UNLOCK(&server->serviceMutex); + return retval; +} + +UA_StatusCode +addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_Double interval_ms, + UA_UInt64 *callbackId) { + return UA_Timer_addRepeatedCallback(&server->timer, + (UA_ApplicationCallback)callback, + server, data, interval_ms, NULL, + UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, callbackId); +} + +UA_StatusCode +UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback, + void *data, UA_Double interval_ms, + UA_UInt64 *callbackId) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = + addRepeatedCallback(server, callback, data, interval_ms, callbackId); + UA_UNLOCK(&server->serviceMutex); + return retval; +} + +UA_StatusCode +changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, + UA_Double interval_ms) { + return UA_Timer_changeRepeatedCallback(&server->timer, callbackId, + interval_ms, NULL, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME); +} + +UA_StatusCode +UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, + UA_Double interval_ms) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = + changeRepeatedCallbackInterval(server, callbackId, interval_ms); + UA_UNLOCK(&server->serviceMutex); + return retval; +} + +void +removeCallback(UA_Server *server, UA_UInt64 callbackId) { + UA_Timer_removeCallback(&server->timer, callbackId); +} + +void +UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId) { + UA_LOCK(&server->serviceMutex); + removeCallback(server, callbackId); + UA_UNLOCK(&server->serviceMutex); +} + +UA_StatusCode +UA_Server_updateCertificate(UA_Server *server, + const UA_ByteString *oldCertificate, + const UA_ByteString *newCertificate, + const UA_ByteString *newPrivateKey, + UA_Boolean closeSessions, + UA_Boolean closeSecureChannels) { + + UA_CHECK(server && oldCertificate && newCertificate && newPrivateKey, + return UA_STATUSCODE_BADINTERNALERROR); + + if(closeSessions) { + session_list_entry *current; + LIST_FOREACH(current, &server->sessions, pointers) { + if(UA_ByteString_equal(oldCertificate, + ¤t->session.header.channel->securityPolicy->localCertificate)) { + UA_LOCK(&server->serviceMutex); + UA_Server_removeSessionByToken(server, ¤t->session.header.authenticationToken, + UA_DIAGNOSTICEVENT_CLOSE); + UA_UNLOCK(&server->serviceMutex); + } + } + + } + + if(closeSecureChannels) { + channel_entry *entry; + TAILQ_FOREACH(entry, &server->channels, pointers) { + if(UA_ByteString_equal(&entry->channel.securityPolicy->localCertificate, oldCertificate)) + UA_Server_closeSecureChannel(server, &entry->channel, UA_DIAGNOSTICEVENT_CLOSE); + } + } + + size_t i = 0; + while(i < server->config.endpointsSize) { + UA_EndpointDescription *ed = &server->config.endpoints[i]; + if(UA_ByteString_equal(&ed->serverCertificate, oldCertificate)) { + UA_String_clear(&ed->serverCertificate); + UA_String_copy(newCertificate, &ed->serverCertificate); + UA_SecurityPolicy *sp = getSecurityPolicyByUri(server, + &server->config.endpoints[i].securityPolicyUri); + UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR); + sp->updateCertificateAndPrivateKey(sp, *newCertificate, *newPrivateKey); + } + i++; + } + + return UA_STATUSCODE_GOOD; +} + +/***************************/ +/* Server lookup functions */ +/***************************/ + +UA_SecurityPolicy * +getSecurityPolicyByUri(const UA_Server *server, const UA_ByteString *securityPolicyUri) { + for(size_t i = 0; i < server->config.securityPoliciesSize; i++) { + UA_SecurityPolicy *securityPolicyCandidate = &server->config.securityPolicies[i]; + if(UA_ByteString_equal(securityPolicyUri, &securityPolicyCandidate->policyUri)) + return securityPolicyCandidate; + } + return NULL; +} + +#ifdef UA_ENABLE_ENCRYPTION +/* The local ApplicationURI has to match the certificates of the + * SecurityPolicies */ +static UA_StatusCode +verifyServerApplicationURI(const UA_Server *server) { + const UA_String securityPolicyNoneUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); + for(size_t i = 0; i < server->config.securityPoliciesSize; i++) { + UA_SecurityPolicy *sp = &server->config.securityPolicies[i]; + if(UA_String_equal(&sp->policyUri, &securityPolicyNoneUri) && (sp->localCertificate.length == 0)) + continue; + UA_StatusCode retval = server->config.certificateVerification. + verifyApplicationURI(server->config.certificateVerification.context, + &sp->localCertificate, + &server->config.applicationDescription.applicationUri); + + UA_CHECK_STATUS_ERROR(retval, return retval, &server->config.logger, UA_LOGCATEGORY_SERVER, + "The configured ApplicationURI \"%.*s\"does not match the " + "ApplicationURI specified in the certificate for the " + "SecurityPolicy %.*s", + (int)server->config.applicationDescription.applicationUri.length, + server->config.applicationDescription.applicationUri.data, + (int)sp->policyUri.length, sp->policyUri.data); + } + return UA_STATUSCODE_GOOD; +} +#endif + +UA_ServerStatistics UA_Server_getStatistics(UA_Server *server) +{ + return server->serverStats; +} + +/********************/ +/* Main Server Loop */ +/********************/ + +#define UA_MAXTIMEOUT 50 /* Max timeout in ms between main-loop iterations */ + +/* 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) { + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Prominently warn user that fuzzing build is enabled. This will tamper with authentication tokens and other important variables + * E.g. if fuzzing is enabled, and two clients are connected, subscriptions do not work properly, + * since the tokens will be overridden to allow easier fuzzing. */ + UA_LOG_FATAL(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Server was built with unsafe fuzzing mode. " + "This should only be used for specific fuzzing builds."); +#endif + + /* ensure that the uri for ns1 is set up from the app description */ + setupNs1Uri(server); + + /* write ServerArray with same ApplicationURI value as NamespaceArray */ + UA_StatusCode retVal = + writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERARRAY, + &server->config.applicationDescription.applicationUri, + 1, &UA_TYPES[UA_TYPES_STRING]); + UA_CHECK_STATUS(retVal, return retVal); + + if(server->state > UA_SERVERLIFECYCLE_FRESH) + return UA_STATUSCODE_GOOD; + + /* At least one endpoint has to be configured */ + if(server->config.endpointsSize == 0) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "There has to be at least one endpoint."); + } + + /* Initialized discovery */ +#ifdef UA_ENABLE_DISCOVERY + UA_DiscoveryManager_init(&server->discoveryManager, server); +#endif + + /* Does the ApplicationURI match the local certificates? */ +#ifdef UA_ENABLE_ENCRYPTION + retVal = verifyServerApplicationURI(server); + UA_CHECK_STATUS(retVal, return retVal); +#endif + + /* Sample the start time and set it to the Server object */ + server->startTime = UA_DateTime_now(); + UA_Variant var; + 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 */ + UA_StatusCode result = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < server->config.networkLayersSize; ++i) { + UA_ServerNetworkLayer *nl = &server->config.networkLayers[i]; + nl->statistics = &server->serverStats.ns; + result |= nl->start(nl, &server->config.logger, &server->config.customHostname); + } + UA_CHECK_STATUS(result, return result); + + /* Update the application description to match the previously added + * discovery urls. We can only do this after the network layer is started + * since it inits the discovery url */ + if(server->config.applicationDescription.discoveryUrlsSize != 0) { + UA_Array_delete(server->config.applicationDescription.discoveryUrls, + server->config.applicationDescription.discoveryUrlsSize, + &UA_TYPES[UA_TYPES_STRING]); + server->config.applicationDescription.discoveryUrlsSize = 0; + } + server->config.applicationDescription.discoveryUrls = (UA_String *) + UA_Array_new(server->config.networkLayersSize, &UA_TYPES[UA_TYPES_STRING]); + UA_CHECK_MEM(server->config.applicationDescription.discoveryUrls, + return UA_STATUSCODE_BADOUTOFMEMORY); + + server->config.applicationDescription.discoveryUrlsSize = + server->config.networkLayersSize; + for(size_t i = 0; i < server->config.applicationDescription.discoveryUrlsSize; i++) { + UA_ServerNetworkLayer *nl = &server->config.networkLayers[i]; + UA_String_copy(&nl->discoveryUrl, + &server->config.applicationDescription.discoveryUrls[i]); + } + + /* Start the multicast discovery server */ +#ifdef UA_ENABLE_DISCOVERY_MULTICAST + if(server->config.mdnsEnabled) + startMulticastDiscoveryServer(server); +#endif + + server->state = UA_SERVERLIFECYCLE_FRESH; + + return result; +} + +static void +serverExecuteRepeatedCallback(UA_Server *server, UA_ApplicationCallback cb, + void *callbackApplication, void *data) { + /* Service mutex is not set inside the timer that triggers the callback */ + /* The following check cannot be used since another thread can take the + * serviceMutex during a server_iterate_call. */ + //UA_LOCK_ASSERT(&server->serviceMutex, 0); + cb(callbackApplication, data); +} + +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_TimerExecutionCallback)serverExecuteRepeatedCallback, 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->ua_listen(nl, server, timeout); + } + +#if defined(UA_ENABLE_PUBSUB_MQTT) + /* Listen on the pubsublayer, but only if the yield function is set */ + UA_PubSubConnection *connection; + TAILQ_FOREACH(connection, &server->pubSubManager.connections, listEntry){ + UA_PubSubConnection *ps = connection; + if(ps && ps->channel->yield){ + ps->channel->yield(ps->channel, timeout); + } + } +#endif + + UA_LOCK(&server->serviceMutex); + +#if defined(UA_ENABLE_DISCOVERY_MULTICAST) && (UA_MULTITHREADING < 200) + if(server->config.mdnsEnabled) { + /* TODO multicastNextRepeat does not consider new input data (requests) + * on the socket. It will be handled on the next call. if needed, we + * need to use select with timeout on the multicast socket + * server->mdnsSocket (see example in mdnsd library) on higher level. */ + UA_DateTime multicastNextRepeat = 0; + UA_StatusCode hasNext = + iterateMulticastDiscoveryServer(server, &multicastNextRepeat, true); + if(hasNext == UA_STATUSCODE_GOOD && multicastNextRepeat < nextRepeated) + nextRepeated = multicastNextRepeat; + } +#endif + + UA_UNLOCK(&server->serviceMutex); + + 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_DISCOVERY_MULTICAST + /* Stop multicast discovery */ + if(server->config.mdnsEnabled) + stopMulticastDiscoveryServer(server); +#endif + + return UA_STATUSCODE_GOOD; +} + +static UA_Boolean +testShutdownCondition(UA_Server *server) { + if(server->endTime == 0) + return false; + return (UA_DateTime_now() > server->endTime); +} + +UA_StatusCode +UA_Server_run(UA_Server *server, const volatile UA_Boolean *running) { + UA_StatusCode retval = UA_Server_run_startup(server); + UA_CHECK_STATUS(retval, return retval); + +#ifdef UA_ENABLE_VALGRIND_INTERACTIVE + size_t loopCount = 0; +#endif + while(!testShutdownCondition(server)) { +#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); + if(!*running) { + if(setServerShutdown(server)) + break; + } + } + return UA_Server_run_shutdown(server); +} + +/**** amalgamated original file "/src/server/ua_server_ns0.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2017-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) Thomas Bender + * Copyright 2017 (c) Julian Grothoff + * Copyright 2017 (c) Henrik Norrman + * Copyright 2018 (c) Fabian Arndt, Root-Core + * Copyright 2019 (c) Kalycito Infotech Private Limited + * Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) + */ + + + +static UA_StatusCode +addNode_raw(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); + UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, + attributes, attributesType); + return AddNode_raw(server, &server->adminSession, NULL, &item, NULL); +} + +static UA_StatusCode +addNode_finish(UA_Server *server, UA_UInt32 nodeId, + UA_UInt32 parentNodeId, UA_UInt32 referenceTypeId) { + const UA_NodeId sourceId = UA_NODEID_NUMERIC(0, nodeId); + const UA_NodeId refTypeId = UA_NODEID_NUMERIC(0, referenceTypeId); + const UA_ExpandedNodeId targetId = UA_EXPANDEDNODEID_NUMERIC(0, parentNodeId); + UA_StatusCode retval = UA_Server_addReference(server, sourceId, refTypeId, targetId, false); + if(retval != UA_STATUSCODE_GOOD) + return retval; + return AddNode_finish(server, &server->adminSession, &sourceId); +} + +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); +} + +/***************************/ +/* Bootstrap NS0 hierarchy */ +/***************************/ + +/* 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) { + /* Bootstrap ReferenceTypes. The order of these is important for the + * ReferenceTypeIndex. The ReferenceTypeIndex is created with the raw node. + * The ReferenceTypeSet of subtypes for every ReferenceType is created + * during the call to AddNode_finish. */ + UA_StatusCode ret = UA_STATUSCODE_GOOD; + UA_ReferenceTypeAttributes references_attr = UA_ReferenceTypeAttributes_default; + references_attr.displayName = UA_LOCALIZEDTEXT("", "References"); + references_attr.isAbstract = true; + references_attr.symmetric = true; + references_attr.inverseName = UA_LOCALIZEDTEXT("", "References"); + ret |= addNode_raw(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_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_HASSUBTYPE, "HasSubtype", + &hassubtype_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]); + + UA_ReferenceTypeAttributes aggregates_attr = UA_ReferenceTypeAttributes_default; + aggregates_attr.displayName = UA_LOCALIZEDTEXT("", "Aggregates"); + aggregates_attr.isAbstract = true; + aggregates_attr.symmetric = false; + aggregates_attr.inverseName = UA_LOCALIZEDTEXT("", "AggregatedBy"); + ret |= addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_AGGREGATES, "Aggregates", + &aggregates_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, true, 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); + + /* Complete bootstrap of Aggregates */ + ret |= addNode_finish(server, UA_NS0ID_AGGREGATES, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE); + + /* 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); + + ret |= addReferenceTypeNode(server, "HasInterface", "InterfaceOf", + UA_NS0ID_HASINTERFACE, false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); + + /**************/ + /* Data Types */ + /**************/ + + /* Bootstrap BaseDataType */ + UA_DataTypeAttributes basedatatype_attr = UA_DataTypeAttributes_default; + basedatatype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataType"); + basedatatype_attr.isAbstract = true; + ret |= addNode_raw(server, UA_NODECLASS_DATATYPE, UA_NS0ID_BASEDATATYPE, "BaseDataType", + &basedatatype_attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]); + + /*****************/ + /* VariableTypes */ + /*****************/ + + 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_raw(server, UA_NODECLASS_VARIABLETYPE, UA_NS0ID_BASEVARIABLETYPE, "BaseVariableType", + &basevar_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]); + + UA_VariableTypeAttributes bdv_attr = UA_VariableTypeAttributes_default; + bdv_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataVariableType"); + bdv_attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE); + bdv_attr.valueRank = UA_VALUERANK_ANY; + ret |= UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE), + UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "BaseDataVariableType"), + UA_NODEID_NULL, bdv_attr, NULL, NULL); + + UA_VariableTypeAttributes prop_attr = UA_VariableTypeAttributes_default; + prop_attr.displayName = UA_LOCALIZEDTEXT("", "PropertyType"); + prop_attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE); + prop_attr.valueRank = UA_VALUERANK_ANY; + ret |= UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE), + UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "PropertyType"), + UA_NODEID_NULL, prop_attr, NULL, NULL); + + /***************/ + /* ObjectTypes */ + /***************/ + + UA_ObjectTypeAttributes baseobj_attr = UA_ObjectTypeAttributes_default; + baseobj_attr.displayName = UA_LOCALIZEDTEXT("", "BaseObjectType"); + ret |= addNode_raw(server, UA_NODECLASS_OBJECTTYPE, UA_NS0ID_BASEOBJECTTYPE, "BaseObjectType", + &baseobj_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]); + + UA_ObjectTypeAttributes folder_attr = UA_ObjectTypeAttributes_default; + folder_attr.displayName = UA_LOCALIZEDTEXT("", "FolderType"); + ret |= UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), + UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "FolderType"), + folder_attr, NULL, NULL); + + /******************/ + /* 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); + + /* Add BaseEventType */ + UA_ObjectTypeAttributes eventtype_attr = UA_ObjectTypeAttributes_default; + eventtype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseEventType"); + ret |= addNode_raw(server, UA_NODECLASS_OBJECTTYPE, UA_NS0ID_BASEEVENTTYPE, "BaseEventType", + &eventtype_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]); + ret |= addNode_finish(server, UA_NS0ID_BASEEVENTTYPE, UA_NS0ID_EVENTTYPESFOLDER, + UA_NS0ID_ORGANIZES); + + if(ret != UA_STATUSCODE_GOOD) + ret = UA_STATUSCODE_BADINTERNALERROR; + + return ret; +} + +/****************/ +/* 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; + } + + if(sourceTimestamp) { + value->hasSourceTimestamp = true; + value->sourceTimestamp = UA_DateTime_now(); + } + + void *data = NULL; + + UA_assert(nodeId->identifierType == UA_NODEIDTYPE_NUMERIC); + + switch(nodeId->identifier.numeric) { + case UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN: { + UA_UInt32 *shutdown = UA_UInt32_new(); + if(!shutdown) + return UA_STATUSCODE_BADOUTOFMEMORY; + if(server->endTime != 0) + *shutdown = (UA_UInt32)((server->endTime - UA_DateTime_now()) / UA_DATETIME_SEC); + value->value.data = shutdown; + value->value.type = &UA_TYPES[UA_TYPES_UINT32]; + value->hasValue = true; + return UA_STATUSCODE_GOOD; + } + + case UA_NS0ID_SERVER_SERVERSTATUS_STATE: { + UA_ServerState *state = UA_ServerState_new(); + if(!state) + return UA_STATUSCODE_BADOUTOFMEMORY; + if(server->endTime != 0) + *state = UA_SERVERSTATE_SHUTDOWN; + value->value.data = state; + value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATE]; + value->hasValue = true; + return UA_STATUSCODE_GOOD; + } + + case UA_NS0ID_SERVER_SERVERSTATUS: { + UA_ServerStatusDataType *statustype = UA_ServerStatusDataType_new(); + if(!statustype) + return UA_STATUSCODE_BADOUTOFMEMORY; + statustype->startTime = server->startTime; + statustype->currentTime = UA_DateTime_now(); + + statustype->state = UA_SERVERSTATE_RUNNING; + statustype->secondsTillShutdown = 0; + if(server->endTime != 0) { + statustype->state = UA_SERVERSTATE_SHUTDOWN; + statustype->secondsTillShutdown = (UA_UInt32) + ((server->endTime - UA_DateTime_now()) / UA_DATETIME_SEC); + } + + value->value.data = statustype; + value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE]; + value->hasValue = true; + return UA_BuildInfo_copy(&server->config.buildInfo, &statustype->buildInfo); + } + + case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO: + value->value.type = &UA_TYPES[UA_TYPES_BUILDINFO]; + data = &server->config.buildInfo; + break; + + case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI: + value->value.type = &UA_TYPES[UA_TYPES_STRING]; + data = &server->config.buildInfo.productUri; + break; + + case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME: + value->value.type = &UA_TYPES[UA_TYPES_STRING]; + data = &server->config.buildInfo.manufacturerName; + break; + + case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME: + value->value.type = &UA_TYPES[UA_TYPES_STRING]; + data = &server->config.buildInfo.productName; + break; + + case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION: + value->value.type = &UA_TYPES[UA_TYPES_STRING]; + data = &server->config.buildInfo.softwareVersion; + break; + + case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER: + value->value.type = &UA_TYPES[UA_TYPES_STRING]; + data = &server->config.buildInfo.buildNumber; + break; + + case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE: + value->value.type = &UA_TYPES[UA_TYPES_DATETIME]; + data = &server->config.buildInfo.buildDate; + break; + + default: + value->hasStatus = true; + value->status = UA_STATUSCODE_BADINTERNALERROR; + return UA_STATUSCODE_GOOD; + } + + value->value.data = UA_new(value->value.type); + if(!value->value.data) { + value->value.type = NULL; + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + value->hasValue = true; + return UA_copy(data, value->value.data, value->value.type); +} + +#ifdef UA_GENERATED_NAMESPACE_ZERO +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; +} +#endif + +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) { + /* ensure that the uri for ns1 is set up from the app description */ + setupNs1Uri(server); + + 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; + + /* ensure that the uri for ns1 is set up from the app description */ + setupNs1Uri(server); + + /* 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; +} + +#ifdef UA_GENERATED_NAMESPACE_ZERO +static UA_StatusCode +readMinSamplingInterval(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; + UA_Duration minInterval; +#ifdef UA_ENABLE_SUBSCRIPTIONS + minInterval = server->config.samplingIntervalLimits.min; +#else + minInterval = 0.0; +#endif + retval = UA_Variant_setScalarCopy(&value->value, &minInterval, &UA_TYPES[UA_TYPES_DURATION]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + value->hasValue = true; + if(includeSourceTimeStamp) { + value->hasSourceTimestamp = true; + value->sourceTimestamp = UA_DateTime_now(); + } + return UA_STATUSCODE_GOOD; +} +#endif + +#if defined(UA_GENERATED_NAMESPACE_ZERO) && 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) { + /* Return two empty arrays by default */ + UA_Variant_setArray(&output[0], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]), + 0, &UA_TYPES[UA_TYPES_UINT32]); + UA_Variant_setArray(&output[1], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]), + 0, &UA_TYPES[UA_TYPES_UINT32]); + + /* Get the Session */ + UA_LOCK(&server->serviceMutex); + UA_Session *session = UA_Server_getSessionById(server, sessionId); + if(!session) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADINTERNALERROR; + } + if(inputSize == 0 || !input[0].data) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + } + + /* Get the Subscription */ + UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data)); + UA_Subscription *subscription = UA_Session_getSubscriptionById(session, subscriptionId); + if(!subscription) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; + } + + /* Count the MonitoredItems */ + UA_UInt32 sizeOfOutput = 0; + UA_MonitoredItem* monitoredItem; + LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) { + ++sizeOfOutput; + } + if(sizeOfOutput == 0) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_GOOD; + } + + /* Allocate the output arrays */ + UA_UInt32 *clientHandles = (UA_UInt32*) + UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); + if(!clientHandles) { + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + UA_UInt32 *serverHandles = (UA_UInt32*) + UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); + if(!serverHandles) { + UA_UNLOCK(&server->serviceMutex); + UA_free(clientHandles); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + /* Fill the array */ + UA_UInt32 i = 0; + LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) { + clientHandles[i] = monitoredItem->parameters.clientHandle; + serverHandles[i] = monitoredItem->monitoredItemId; + ++i; + } + UA_Variant_setArray(&output[0], serverHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); + UA_Variant_setArray(&output[1], clientHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); + + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_GOOD; +} +#endif /* defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) */ + +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); +} + +#ifndef UA_GENERATED_NAMESPACE_ZERO +static UA_StatusCode +addVariableNode(UA_Server *server, char* name, UA_UInt32 variableid, + UA_UInt32 parentid, UA_UInt32 referenceid, + UA_Int32 valueRank, UA_UInt32 dataType) { + UA_VariableAttributes attr = UA_VariableAttributes_default; + attr.displayName = UA_LOCALIZEDTEXT("", name); + attr.dataType = UA_NODEID_NUMERIC(0, dataType); + attr.valueRank = valueRank; + attr.accessLevel = UA_ACCESSLEVELMASK_READ; + return UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(0, variableid), + UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NUMERIC(0, referenceid), + UA_QUALIFIEDNAME(0, name), + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + attr, NULL, NULL); +} + +/* A minimal server object that is not complete and does not use the mandated + * references to a server type. To be used on very constrained devices. */ +static UA_StatusCode +UA_Server_minimalServerObject(UA_Server *server) { + /* Server */ + UA_StatusCode retval = addObjectNode(server, "Server", UA_NS0ID_SERVER, UA_NS0ID_OBJECTSFOLDER, + UA_NS0ID_ORGANIZES, UA_NS0ID_BASEOBJECTTYPE); + + /* Use a valuerank of -2 for now. The array is added later on and the valuerank set to 1. */ + retval |= addVariableNode(server, "ServerArray", UA_NS0ID_SERVER_SERVERARRAY, + UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY, + UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "NamespaceArray", UA_NS0ID_SERVER_NAMESPACEARRAY, + UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY, + UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "ServerStatus", UA_NS0ID_SERVER_SERVERSTATUS, + UA_NS0ID_SERVER, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "CurrentTime", UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME, + UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "State", UA_NS0ID_SERVER_SERVERSTATUS_STATE, + UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "BuildInfo", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, + UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "ProductUri", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI, + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "ManufacturerName", + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME, + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "ProductName", + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME, + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "SoftwareVersion", + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION, + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "BuildNumber", + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER, + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + retval |= addVariableNode(server, "BuildDate", + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE, + UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, + UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); + + return retval; +} + +#else + +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 void +addModellingRules(UA_Server *server) { + /* Test if the ModellingRules folder was added. (Only for the full ns0.) */ + UA_NodeClass mrnc = UA_NODECLASS_UNSPECIFIED; + UA_StatusCode retval = UA_Server_readNodeClass(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES), + &mrnc); + if(retval != UA_STATUSCODE_GOOD) + return; + + /* Add ExposesItsArray */ + UA_Server_addReference(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_EXPOSESITSARRAY), + true); + + /* Add Mandatory */ + UA_Server_addReference(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), + true); + + + /* Add MandatoryPlaceholder */ + UA_Server_addReference(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORYPLACEHOLDER), + true); + + /* Add Optional */ + UA_Server_addReference(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_OPTIONAL), + true); + + /* Add OptionalPlaceholder */ + UA_Server_addReference(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES), + UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), + UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_OPTIONALPLACEHOLDER), + true); +} + +#endif + +/* 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); + +#ifdef UA_GENERATED_NAMESPACE_ZERO + /* Load nodes and references generated from the XML ns0 definition */ + retVal |= namespace0_generated(server); +#else + /* Create a minimal server object */ + retVal |= UA_Server_minimalServerObject(server); +#endif + + server->bootstrapNS0 = false; + + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Initialization of Namespace 0 failed with %s. " + "See previous outputs for any error messages.", + UA_StatusCode_name(retVal)); + return UA_STATUSCODE_BADINTERNALERROR; + } + + /* NamespaceArray */ + UA_DataSource namespaceDataSource = {readNamespaces, writeNamespaces}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), + namespaceDataSource); + retVal |= UA_Server_writeValueRank(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), 1); + + /* ServerArray */ + retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERARRAY, + &server->config.applicationDescription.applicationUri, + 1, &UA_TYPES[UA_TYPES_STRING]); + retVal |= UA_Server_writeValueRank(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY), 1); + + /* 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}; + UA_NodeId currTime = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); + retVal |= UA_Server_setVariableNode_dataSource(server, currTime, currentTime); + retVal |= UA_Server_writeMinimumSamplingInterval(server, currTime, 100.0); + + /* State */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE), + serverStatus); + + /* BuildInfo */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), serverStatus); + + /* BuildInfo - ProductUri */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI), + serverStatus); + + /* BuildInfo - ManufacturerName */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME), + serverStatus); + + /* BuildInfo - ProductName */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME), + serverStatus); + + /* BuildInfo - SoftwareVersion */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION), + serverStatus); + + /* BuildInfo - BuildNumber */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER), + serverStatus); + + /* BuildInfo - BuildDate */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE), + serverStatus); + +#ifdef UA_GENERATED_NAMESPACE_ZERO + + /* SecondsTillShutdown */ + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN), + serverStatus); + + /* 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); + + /* 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]); + + /* According to Specification part-5 - pg.no-11(PDF pg.no-29), when the ServerDiagnostics is disabled the client + * may modify the value of enabledFlag=true in the server. By default, this node have CurrentRead/Write access. + * In CTT, Subscription_Minimum_1/002.js test will modify the above flag. This will not be a problem when build + * configuration is set at UA_NAMESPACE_ZERO="REDUCED" as NodeIds will not be present. When UA_NAMESPACE_ZERO="FULL", + * the test will fail. Hence made the NodeId as read only */ + retVal |= UA_Server_writeAccessLevel(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG), + UA_ACCESSLEVELMASK_READ); + + /* Auditing */ + UA_DataSource auditing = {readAuditing, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_AUDITING), auditing); + + /* Redundancy Support */ + UA_RedundancySupport redundancySupport = UA_REDUNDANCYSUPPORT_NONE; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANCYSUPPORT, + &redundancySupport, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]); + + /* Remove unused subtypes of ServerRedundancy */ + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_CURRENTSERVERID), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANTSERVERARRAY), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_SERVERURIARRAY), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_SERVERNETWORKGROUPS), true); + + /* ServerCapabilities - LocaleIdArray */ + UA_LocaleId locale_en = UA_STRING("en"); + retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY, + &locale_en, 1, &UA_TYPES[UA_TYPES_LOCALEID]); + + /* ServerCapabilities - MaxBrowseContinuationPoints */ + UA_UInt16 maxBrowseContinuationPoints = UA_MAXCONTINUATIONPOINTS; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS, + &maxBrowseContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]); + + /* ServerProfileArray */ + UA_String profileArray[3]; + UA_UInt16 profileArraySize = 0; +#define ADDPROFILEARRAY(x) profileArray[profileArraySize++] = UA_STRING(x) + ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/MicroEmbeddedDevice"); +#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 + retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY, + profileArray, profileArraySize, &UA_TYPES[UA_TYPES_STRING]); + + /* ServerCapabilities - MaxQueryContinuationPoints */ + UA_UInt16 maxQueryContinuationPoints = 0; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXQUERYCONTINUATIONPOINTS, + &maxQueryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]); + + /* ServerCapabilities - MaxHistoryContinuationPoints */ + UA_UInt16 maxHistoryContinuationPoints = 0; + retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXHISTORYCONTINUATIONPOINTS, + &maxHistoryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]); + + /* ServerCapabilities - MinSupportedSampleRate */ + UA_DataSource samplingInterval = {readMinSamplingInterval, NULL}; + retVal |= UA_Server_setVariableNode_dataSource(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MINSUPPORTEDSAMPLERATE), + samplingInterval); + + /* 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]); + + /* Remove unused operation limit components */ + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADDATA), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADEVENTS), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYUPDATEDATA), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYUPDATEEVENTS), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_ROLESET), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXSTRINGLENGTH), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXARRAYLENGTH), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBYTESTRINGLENGTH), true); + + /* Remove not supported server configurations */ + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_ESTIMATEDRETURNTIME), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_LOCALTIME), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_REQUESTSERVERSTATECHANGE), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_RESENDDATA), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SETSUBSCRIPTIONDURABLE), true); + + /* Remove unused diagnostics */ + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SAMPLINGINTERVALDIAGNOSTICSARRAY), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY), true); + + /* Removing these NodeIds make Server Object to be non-complaint with UA 1.03 in CTT (Base Inforamtion/Base Info Core Structure/ 001.js) + * In the 1.04 specification this has been resolved by allowing to remove these static nodes as well */ + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY), true); + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY), true); + +#ifndef UA_ENABLE_PUBSUB + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), true); +#endif + +#ifndef UA_ENABLE_HISTORIZING + UA_Server_deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_HISTORYSERVERCAPABILITIES), true); +#else + /* ServerCapabilities - HistoryServerCapabilities - AccessHistoryDataCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_ACCESSHISTORYDATACAPABILITY, + &server->config.accessHistoryDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - MaxReturnDataValues */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_MAXRETURNDATAVALUES, + &server->config.maxReturnDataValues, &UA_TYPES[UA_TYPES_UINT32]); + + /* ServerCapabilities - HistoryServerCapabilities - AccessHistoryEventsCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_ACCESSHISTORYEVENTSCAPABILITY, + &server->config.accessHistoryEventsCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - MaxReturnEventValues */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_MAXRETURNEVENTVALUES, + &server->config.maxReturnEventValues, &UA_TYPES[UA_TYPES_UINT32]); + + /* ServerCapabilities - HistoryServerCapabilities - InsertDataCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTDATACAPABILITY, + &server->config.insertDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - InsertEventCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTEVENTCAPABILITY, + &server->config.insertEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - InsertAnnotationsCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTANNOTATIONCAPABILITY, + &server->config.insertAnnotationsCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - ReplaceDataCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_REPLACEDATACAPABILITY, + &server->config.replaceDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - ReplaceEventCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_REPLACEEVENTCAPABILITY, + &server->config.replaceEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - UpdateDataCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_UPDATEDATACAPABILITY, + &server->config.updateDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - UpdateEventCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_UPDATEEVENTCAPABILITY, + &server->config.updateEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - DeleteRawCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETERAWCAPABILITY, + &server->config.deleteRawCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - DeleteEventCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETEEVENTCAPABILITY, + &server->config.deleteEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); + + /* ServerCapabilities - HistoryServerCapabilities - DeleteAtTimeDataCapability */ + retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETEATTIMECAPABILITY, + &server->config.deleteAtTimeDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); +#endif + +#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) + retVal |= UA_Server_setMethodNodeCallback(server, + UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), readMonitoredItems); +#endif + + /* The HasComponent references to the ModellingRules are not part of the + * Nodeset2.xml. So we add the references manually. */ + addModellingRules(server); + +#endif /* UA_GENERATED_NAMESPACE_ZERO */ + + if(retVal != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Initialization of Namespace 0 (after bootstrapping) " + "failed with %s. See previous outputs for any error messages.", + UA_StatusCode_name(retVal)); + return UA_STATUSCODE_BADINTERNALERROR; + } + return UA_STATUSCODE_GOOD; +} + +/**** amalgamated original file "/src/server/ua_server_config.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green) + */ + + +void +UA_ServerConfig_clean(UA_ServerConfig *config) { + if(!config) + return; + + /* Server Description */ + UA_BuildInfo_clear(&config->buildInfo); + UA_ApplicationDescription_clear(&config->applicationDescription); +#ifdef UA_ENABLE_DISCOVERY_MULTICAST + UA_MdnsDiscoveryConfiguration_clear(&config->mdnsConfig); + UA_String_clear(&config->mdnsInterfaceIP); +# if !defined(UA_HAS_GETIFADDR) + if (config->mdnsIpAddressListSize) { + UA_free(config->mdnsIpAddressList); + } +# endif +#endif + + /* Custom DataTypes */ + /* nothing to do */ + + /* Networking */ + for(size_t i = 0; i < config->networkLayersSize; ++i) + config->networkLayers[i].clear(&config->networkLayers[i]); + UA_free(config->networkLayers); + config->networkLayers = NULL; + config->networkLayersSize = 0; + UA_String_clear(&config->customHostname); + config->customHostname = UA_STRING_NULL; + + for(size_t i = 0; i < config->securityPoliciesSize; ++i) { + UA_SecurityPolicy *policy = &config->securityPolicies[i]; + policy->clear(policy); + } + UA_free(config->securityPolicies); + config->securityPolicies = NULL; + config->securityPoliciesSize = 0; + + for(size_t i = 0; i < config->endpointsSize; ++i) + UA_EndpointDescription_clear(&config->endpoints[i]); + + UA_free(config->endpoints); + config->endpoints = NULL; + config->endpointsSize = 0; + + /* Nodestore */ + if(config->nodestore.context && config->nodestore.clear) { + config->nodestore.clear(config->nodestore.context); + config->nodestore.context = NULL; + } + + /* Certificate Validation */ + if(config->certificateVerification.clear) + config->certificateVerification.clear(&config->certificateVerification); + + /* Access Control */ + if(config->accessControl.clear) + config->accessControl.clear(&config->accessControl); + + /* Historical data */ +#ifdef UA_ENABLE_HISTORIZING + if(config->historyDatabase.clear) + config->historyDatabase.clear(&config->historyDatabase); +#endif + + /* Logger */ + if(config->logger.clear) + config->logger.clear(config->logger.context); + config->logger.log = NULL; + config->logger.clear = NULL; + +#ifdef UA_ENABLE_PUBSUB +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + if(config->pubSubConfig.securityPolicies != NULL) { + for(size_t i = 0; i < config->pubSubConfig.securityPoliciesSize; i++) { + config->pubSubConfig.securityPolicies[i].clear(&config->pubSubConfig.securityPolicies[i]); + } + UA_free(config->pubSubConfig.securityPolicies); + config->pubSubConfig.securityPolicies = NULL; + config->pubSubConfig.securityPoliciesSize = 0; + } +#endif +#endif /* UA_ENABLE_PUBSUB */ +} + +#ifdef UA_ENABLE_PUBSUB +/* Add a pubsubTransportLayer to the configuration. Memory is reallocated on + * demand. */ +UA_StatusCode +UA_ServerConfig_addPubSubTransportLayer(UA_ServerConfig *config, + UA_PubSubTransportLayer pubsubTransportLayer) { + UA_PubSubTransportLayer *tmpLayers = (UA_PubSubTransportLayer*) + UA_realloc(config->pubSubConfig.transportLayers, + sizeof(UA_PubSubTransportLayer) * + (config->pubSubConfig.transportLayersSize + 1)); + if(tmpLayers == NULL) + return UA_STATUSCODE_BADOUTOFMEMORY; + + config->pubSubConfig.transportLayers = tmpLayers; + config->pubSubConfig.transportLayers[config->pubSubConfig.transportLayersSize] = pubsubTransportLayer; + config->pubSubConfig.transportLayersSize++; + return UA_STATUSCODE_GOOD; +} +#endif /* UA_ENABLE_PUBSUB */ + +/**** amalgamated original file "/src/server/ua_server_binary.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2014-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 + * Copyright 2019 (c) Kalycito Infotech Private Limited + */ + + + +#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 */ +/********************/ + +UA_StatusCode +sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, UA_UInt32 requestHandle, + const UA_DataType *responseType, UA_StatusCode statusCode) { + UA_Response response; + UA_init(&response, responseType); + UA_ResponseHeader *responseHeader = &response.responseHeader; + responseHeader->requestHandle = requestHandle; + responseHeader->timestamp = UA_DateTime_now(); + responseHeader->serviceResult = statusCode; + + UA_LOG_DEBUG(channel->securityPolicy->logger, UA_LOGCATEGORY_SERVER, + "Sending response for RequestId %u with ServiceResult %s", + (unsigned)requestId, UA_StatusCode_name(statusCode)); + + /* Send error message. Message type is MSG and not ERR, since we are on a + * SecureChannel! */ + return UA_SecureChannel_sendSymmetricMessage(channel, requestId, UA_MESSAGETYPE_MSG, + &response, responseType); +} + + /* This is not an ERR message, the connection is not closed afterwards */ +static UA_StatusCode +decodeHeaderSendServiceFault(UA_SecureChannel *channel, const UA_ByteString *msg, + size_t offset, const UA_DataType *responseType, + UA_UInt32 requestId, UA_StatusCode error) { + UA_RequestHeader requestHeader; + UA_StatusCode retval = + UA_decodeBinaryInternal(msg, &offset, &requestHeader, + &UA_TYPES[UA_TYPES_REQUESTHEADER], NULL); + if(retval != UA_STATUSCODE_GOOD) + return retval; + retval = sendServiceFault(channel, requestId, requestHeader.requestHandle, + responseType, error); + UA_RequestHeader_clear(&requestHeader); + return retval; +} + +static void +getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType, + const UA_DataType **responseType, UA_Service *service, + UA_Boolean *requiresSession) { + 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 = (UA_Service)Service_CreateSession; + *requestType = &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]; + *requiresSession = false; + break; + case UA_NS0ID_ACTIVATESESSIONREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_ActivateSession; + *requestType = &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]; + 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; + *service = (UA_Service)Service_Read; + *requestType = &UA_TYPES[UA_TYPES_READREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_READRESPONSE]; + 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_TRANSFERSUBSCRIPTIONSREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_TransferSubscriptions; + *requestType = &UA_TYPES[UA_TYPES_TRANSFERSUBSCRIPTIONSREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_TRANSFERSUBSCRIPTIONSRESPONSE]; + 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; + case UA_NS0ID_SETTRIGGERINGREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_SetTriggering; + *requestType = &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]; + break; +#endif +#ifdef UA_ENABLE_HISTORIZING + /* For History read */ + case UA_NS0ID_HISTORYREADREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_HistoryRead; + *requestType = &UA_TYPES[UA_TYPES_HISTORYREADREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]; + break; + /* For History update */ + case UA_NS0ID_HISTORYUPDATEREQUEST_ENCODING_DEFAULTBINARY: + *service = (UA_Service)Service_HistoryUpdate; + *requestType = &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST]; + *responseType = &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]; + 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_SecureChannel *channel, const UA_ByteString *msg) { + if(channel->state != UA_SECURECHANNELSTATE_FRESH) + return UA_STATUSCODE_BADINTERNALERROR; + size_t offset = 0; /* Go to the beginning of the TcpHelloMessage */ + UA_TcpHelloMessage helloMessage; + UA_StatusCode retval = + UA_decodeBinaryInternal(msg, &offset, &helloMessage, + &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE], NULL); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Currently not checked */ + UA_String_clear(&helloMessage.endpointUrl); + + /* Parameterize the connection. The TcpHelloMessage casts to a + * TcpAcknowledgeMessage. */ + retval = UA_SecureChannel_processHELACK(channel, + (UA_TcpAcknowledgeMessage*)&helloMessage); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Error during the HEL/ACK handshake", + (int)(channel->connection->sockfd)); + return retval; + } + + /* Get the send buffer from the network layer */ + UA_Connection *connection = channel->connection; + UA_ByteString ack_msg; + UA_ByteString_init(&ack_msg); + retval = connection->getSendBuffer(connection, channel->config.sendBufferSize, &ack_msg); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Build acknowledge response */ + UA_TcpAcknowledgeMessage ackMessage; + ackMessage.protocolVersion = 0; + ackMessage.receiveBufferSize = channel->config.recvBufferSize; + ackMessage.sendBufferSize = channel->config.sendBufferSize; + ackMessage.maxMessageSize = channel->config.localMaxMessageSize; + ackMessage.maxChunkCount = channel->config.localMaxChunkCount; + + UA_TcpMessageHeader ackHeader; + ackHeader.messageTypeAndChunkType = UA_MESSAGETYPE_ACK + UA_CHUNKTYPE_FINAL; + ackHeader.messageSize = 8 + 20; /* ackHeader + ackMessage */ + + /* Encode and send the response */ + UA_Byte *bufPos = ack_msg.data; + const UA_Byte *bufEnd = &ack_msg.data[ack_msg.length]; + retval |= UA_encodeBinaryInternal(&ackHeader, + &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], + &bufPos, &bufEnd, NULL, NULL); + retval |= UA_encodeBinaryInternal(&ackMessage, + &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE], + &bufPos, &bufEnd, NULL, NULL); + if(retval != UA_STATUSCODE_GOOD) { + connection->releaseSendBuffer(connection, &ack_msg); + return retval; + } + + ack_msg.length = ackHeader.messageSize; + retval = connection->ua_send(connection, &ack_msg); + if(retval == UA_STATUSCODE_GOOD) + channel->state = UA_SECURECHANNELSTATE_ACK_SENT; + return retval; +} + +/* OPN -> Open up/renew the securechannel */ +static UA_StatusCode +processOPN(UA_Server *server, UA_SecureChannel *channel, + const UA_UInt32 requestId, const UA_ByteString *msg) { + if(channel->state != UA_SECURECHANNELSTATE_ACK_SENT && + channel->state != UA_SECURECHANNELSTATE_OPEN) + return UA_STATUSCODE_BADINTERNALERROR; + /* Decode the request */ + UA_NodeId requestType; + UA_OpenSecureChannelRequest openSecureChannelRequest; + size_t offset = 0; + UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &requestType); + if(retval != UA_STATUSCODE_GOOD) { + UA_NodeId_clear(&requestType); + UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, + "Could not decode the NodeId. Closing the connection"); + UA_Server_closeSecureChannel(server, channel, UA_DIAGNOSTICEVENT_REJECT); + return retval; + } + retval = UA_decodeBinaryInternal(msg, &offset, &openSecureChannelRequest, + &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST], NULL); + + /* Error occurred */ + if(retval != UA_STATUSCODE_GOOD || + !UA_NodeId_equal(&requestType, &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST].binaryEncodingId)) { + UA_NodeId_clear(&requestType); + UA_OpenSecureChannelRequest_clear(&openSecureChannelRequest); + UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, + "Could not decode the OPN message. Closing the connection."); + UA_Server_closeSecureChannel(server, channel, UA_DIAGNOSTICEVENT_REJECT); + return retval; + } + UA_NodeId_clear(&requestType); + + /* Call the service */ + UA_OpenSecureChannelResponse openScResponse; + UA_OpenSecureChannelResponse_init(&openScResponse); + Service_OpenSecureChannel(server, channel, &openSecureChannelRequest, &openScResponse); + UA_OpenSecureChannelRequest_clear(&openSecureChannelRequest); + if(openScResponse.responseHeader.serviceResult != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, "Could not open a SecureChannel. " + "Closing the connection."); + UA_Server_closeSecureChannel(server, channel, UA_DIAGNOSTICEVENT_REJECT); + return openScResponse.responseHeader.serviceResult; + } + + /* Send the response */ + retval = UA_SecureChannel_sendAsymmetricOPNMessage(channel, requestId, &openScResponse, + &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]); + UA_OpenSecureChannelResponse_clear(&openScResponse); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, + "Could not send the OPN answer with error code %s", + UA_StatusCode_name(retval)); + UA_Server_closeSecureChannel(server, channel, UA_DIAGNOSTICEVENT_REJECT); + } + + return retval; +} + +/* The responseHeader must have the requestHandle already set */ +UA_StatusCode +sendResponse(UA_Server *server, UA_Session *session, UA_SecureChannel *channel, + UA_UInt32 requestId, UA_Response *response, const UA_DataType *responseType) { + if(!channel) + return UA_STATUSCODE_BADINTERNALERROR; + + /* Prepare the ResponseHeader */ + response->responseHeader.timestamp = UA_DateTime_now(); + + if(session) { +#ifdef UA_ENABLE_TYPEDESCRIPTION + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Sending response for RequestId %u of type %s", + (unsigned)requestId, responseType->typeName); +#else + UA_LOG_DEBUG_SESSION(&server->config.logger, session, + "Sending reponse for RequestId %u of type %" PRIu32, + (unsigned)requestId, responseType->binaryEncodingId.identifier.numeric); +#endif + } else { +#ifdef UA_ENABLE_TYPEDESCRIPTION + UA_LOG_DEBUG_CHANNEL(&server->config.logger, channel, + "Sending response for RequestId %u of type %s", + (unsigned)requestId, responseType->typeName); +#else + UA_LOG_DEBUG_CHANNEL(&server->config.logger, channel, + "Sending reponse for RequestId %u of type %" PRIu32, + (unsigned)requestId, responseType->binaryEncodingId.identifier.numeric); +#endif + } + + /* Start the message context */ + UA_MessageContext mc; + UA_StatusCode retval = UA_MessageContext_begin(&mc, channel, requestId, UA_MESSAGETYPE_MSG); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Assert's required for clang-analyzer */ + UA_assert(mc.buf_pos == &mc.messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]); + UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]); + + /* Encode the response type */ + retval = UA_MessageContext_encode(&mc, &responseType->binaryEncodingId, + &UA_TYPES[UA_TYPES_NODEID]); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Encode the response */ + retval = UA_MessageContext_encode(&mc, response, responseType); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Finish / send out */ + return UA_MessageContext_finish(&mc); +} + +/* A Session is "bound" to a SecureChannel if it was created by the + * SecureChannel or if it was activated on it. A Session can only be bound to + * one SecureChannel. A Session can only be closed from the SecureChannel to + * which it is bound. + * + * Returns Good if the AuthenticationToken exists nowhere (for CTT). */ +UA_StatusCode +getBoundSession(UA_Server *server, const UA_SecureChannel *channel, + const UA_NodeId *token, UA_Session **session) { + UA_DateTime now = UA_DateTime_nowMonotonic(); + UA_SessionHeader *sh; + SLIST_FOREACH(sh, &channel->sessions, next) { + if(!UA_NodeId_equal(token, &sh->authenticationToken)) + continue; + UA_Session *current = (UA_Session*)sh; + /* Has the session timed out? */ + if(current->validTill < now) + return UA_STATUSCODE_BADSESSIONCLOSED; + *session = current; + return UA_STATUSCODE_GOOD; + } + + /* Session exists on another SecureChannel. The CTT expect this error. */ + if(getSessionByToken(server, token)) + return UA_STATUSCODE_BADSECURECHANNELIDINVALID; + + return UA_STATUSCODE_GOOD; +} + +static const UA_String securityPolicyNone = + UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#None"); + +static UA_StatusCode +processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId, + UA_Service service, const UA_Request *request, + const UA_DataType *requestType, UA_Response *response, + const UA_DataType *responseType, UA_Boolean sessionRequired) { + const UA_RequestHeader *requestHeader = &request->requestHeader; + + /* If it is an unencrypted (#None) channel, only allow the discovery services */ + if(server->config.securityPolicyNoneDiscoveryOnly && + UA_String_equal(&channel->securityPolicy->policyUri, &securityPolicyNone ) && + requestType != &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST] && + requestType != &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST] +#if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST) + && requestType != &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST] +#endif + ) { + return sendServiceFault(channel, requestId, requestHeader->requestHandle, + responseType, UA_STATUSCODE_BADSECURITYPOLICYREJECTED); + } + + /* Session lifecycle services. */ + if(requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST] || + requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST] || + requestType == &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST]) { + UA_LOCK(&server->serviceMutex); + ((UA_ChannelService)service)(server, channel, request, response); + UA_UNLOCK(&server->serviceMutex); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Store the authentication token so we can help fuzzing by setting + * these values in the next request automatically */ + if(requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]) { + UA_CreateSessionResponse *res = &response->createSessionResponse; + UA_NodeId_copy(&res->authenticationToken, &unsafe_fuzz_authenticationToken); + } +#endif + return sendResponse(server, NULL, channel, requestId, response, responseType); + } + + /* Get the Session bound to the SecureChannel (not necessarily activated) */ + UA_Session *session = NULL; + if(!UA_NodeId_isNull(&requestHeader->authenticationToken)) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = getBoundSession( + server, channel, &requestHeader->authenticationToken, &session); + UA_UNLOCK(&server->serviceMutex); + if(retval != UA_STATUSCODE_GOOD) + return sendServiceFault(channel, requestId, requestHeader->requestHandle, + responseType, retval); + } + + /* Set an anonymous, inactive session for services that need no session */ + UA_Session anonymousSession; + if(!session) { + if(sessionRequired) { +#ifdef UA_ENABLE_TYPEDESCRIPTION + UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, + "%s refused without a valid session", + requestType->typeName); +#else + UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, + "Service %" PRIu32 " refused without a valid session", + requestType->binaryEncodingId.identifier.numeric); +#endif + return sendServiceFault(channel, requestId, requestHeader->requestHandle, + responseType, UA_STATUSCODE_BADSESSIONIDINVALID); + } + + UA_Session_init(&anonymousSession); + anonymousSession.sessionId = UA_NODEID_GUID(0, UA_GUID_NULL); + anonymousSession.header.channel = channel; + session = &anonymousSession; + } + + UA_assert(session != NULL); + + /* Trying to use a non-activated session? */ + if(sessionRequired && !session->activated) { +#ifdef UA_ENABLE_TYPEDESCRIPTION + UA_LOG_WARNING_SESSION(&server->config.logger, session, + "%s refused on a non-activated session", + requestType->typeName); +#else + UA_LOG_WARNING_SESSION(&server->config.logger, session, + "Service %" PRIu32 " refused on a non-activated session", + requestType->binaryEncodingId.identifier.numeric); +#endif + if(session != &anonymousSession) { + UA_LOCK(&server->serviceMutex); + UA_Server_removeSessionByToken(server, &session->header.authenticationToken, + UA_DIAGNOSTICEVENT_ABORT); + UA_UNLOCK(&server->serviceMutex); + } + return sendServiceFault(channel, requestId, requestHeader->requestHandle, + responseType, UA_STATUSCODE_BADSESSIONNOTACTIVATED); + } + + /* 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]) { + UA_LOCK(&server->serviceMutex); + Service_Publish(server, session, &request->publishRequest, requestId); + UA_UNLOCK(&server->serviceMutex); + return UA_STATUSCODE_GOOD; + } +#endif + +#if UA_MULTITHREADING >= 100 + /* The call request might not be answered immediately */ + if(requestType == &UA_TYPES[UA_TYPES_CALLREQUEST]) { + UA_Boolean finished = true; + UA_LOCK(&server->serviceMutex); + Service_CallAsync(server, session, requestId, &request->callRequest, + &response->callResponse, &finished); + UA_UNLOCK(&server->serviceMutex); + + /* Async method calls remain. Don't send a response now */ + if(!finished) + return UA_STATUSCODE_GOOD; + + /* We are done here */ + return sendResponse(server, session, channel, requestId, response, responseType); + } +#endif + + /* Dispatch the synchronous service call and send the response */ + UA_LOCK(&server->serviceMutex); + service(server, session, request, response); + UA_UNLOCK(&server->serviceMutex); + return sendResponse(server, session, channel, requestId, response, responseType); +} + +static UA_StatusCode +processMSG(UA_Server *server, UA_SecureChannel *channel, + UA_UInt32 requestId, const UA_ByteString *msg) { + if(channel->state != UA_SECURECHANNELSTATE_OPEN) + return UA_STATUSCODE_BADINTERNALERROR; + /* Decode the nodeid */ + size_t offset = 0; + UA_NodeId requestTypeId; + 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_clear(&requestTypeId); /* leads to badserviceunsupported */ + + size_t requestPos = offset; /* Store the offset (for sendServiceFault) */ + + /* Get the service pointers */ + UA_Service service = NULL; + UA_Boolean sessionRequired = true; + const UA_DataType *requestType = NULL; + const UA_DataType *responseType = NULL; + getServicePointers(requestTypeId.identifier.numeric, &requestType, + &responseType, &service, &sessionRequired); + if(!requestType) { + if(requestTypeId.identifier.numeric == + UA_NS0ID_CREATESUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY) { + 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 %" PRIi32, + requestTypeId.identifier.numeric); + } + return decodeHeaderSendServiceFault(channel, msg, requestPos, + &UA_TYPES[UA_TYPES_SERVICEFAULT], + requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED); + } + UA_assert(responseType); + + /* Decode the request */ + UA_Request request; + retval = UA_decodeBinaryInternal(msg, &offset, &request, + requestType, server->config.customDataTypes); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_DEBUG_CHANNEL(&server->config.logger, channel, + "Could not decode the request with StatusCode %s", + UA_StatusCode_name(retval)); + return decodeHeaderSendServiceFault(channel, msg, requestPos, + responseType, requestId, retval); + } + + /* Check timestamp in the request header */ + UA_RequestHeader *requestHeader = &request.requestHeader; + if(requestHeader->timestamp == 0) { + if(server->config.verifyRequestTimestamp <= UA_RULEHANDLING_WARN) { + UA_LOG_WARNING_CHANNEL(&server->config.logger, channel, + "The server sends no timestamp in the request header. " + "See the 'verifyRequestTimestamp' setting."); + if(server->config.verifyRequestTimestamp <= UA_RULEHANDLING_ABORT) { + retval = sendServiceFault(channel, requestId, requestHeader->requestHandle, + responseType, UA_STATUSCODE_BADINVALIDTIMESTAMP); + UA_clear(&request, requestType); + return retval; + } + } + } + +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Set the authenticationToken from the create session request to help + * fuzzing cover more lines */ + if(!UA_NodeId_isNull(&unsafe_fuzz_authenticationToken) && + !UA_NodeId_isNull(&requestHeader->authenticationToken)) { + UA_NodeId_clear(&requestHeader->authenticationToken); + UA_NodeId_copy(&unsafe_fuzz_authenticationToken, &requestHeader->authenticationToken); + } +#endif + + /* Prepare the respone and process the request */ + UA_Response response; + UA_init(&response, responseType); + response.responseHeader.requestHandle = requestHeader->requestHandle; + retval = processMSGDecoded(server, channel, requestId, service, &request, requestType, + &response, responseType, sessionRequired); + + /* Clean up */ + UA_clear(&request, requestType); + UA_clear(&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, + UA_ByteString *message) { + UA_Server *server = (UA_Server*)application; + + UA_StatusCode retval = UA_STATUSCODE_GOOD; + switch(messagetype) { + case UA_MESSAGETYPE_HEL: + UA_LOG_TRACE_CHANNEL(&server->config.logger, channel, "Process a HEL message"); + retval = processHEL(server, channel, message); + break; + case UA_MESSAGETYPE_OPN: + UA_LOG_TRACE_CHANNEL(&server->config.logger, channel, "Process an OPN message"); + 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); /* Regular close */ + break; + default: + UA_LOG_TRACE_CHANNEL(&server->config.logger, channel, "Invalid message type"); + retval = UA_STATUSCODE_BADTCPMESSAGETYPEINVALID; + break; + } + if(retval != UA_STATUSCODE_GOOD) { + if(!channel->connection) { + UA_LOG_INFO_CHANNEL(&server->config.logger, channel, + "Processing the message failed. Channel already closed " + "with StatusCode %s. ", UA_StatusCode_name(retval)); + return retval; + } + + UA_LOG_INFO_CHANNEL(&server->config.logger, channel, + "Processing the message failed with StatusCode %s. " + "Closing the channel.", UA_StatusCode_name(retval)); + UA_TcpErrorMessage errMsg; + UA_TcpErrorMessage_init(&errMsg); + errMsg.error = retval; + UA_Connection_sendError(channel->connection, &errMsg); + switch(retval) { + case UA_STATUSCODE_BADSECURITYMODEREJECTED: + case UA_STATUSCODE_BADSECURITYCHECKSFAILED: + case UA_STATUSCODE_BADSECURECHANNELIDINVALID: + case UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN: + case UA_STATUSCODE_BADSECURITYPOLICYREJECTED: + case UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED: + UA_Server_closeSecureChannel(server, channel, UA_DIAGNOSTICEVENT_SECURITYREJECT); + break; + default: + UA_Server_closeSecureChannel(server, channel, UA_DIAGNOSTICEVENT_CLOSE); + break; + } + } + + return retval; +} + +void +UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, + UA_ByteString *message) { + UA_LOG_TRACE(&server->config.logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Received a packet.", (int)(connection->sockfd)); + + UA_TcpErrorMessage error; + UA_StatusCode retval = UA_STATUSCODE_GOOD; + UA_SecureChannel *channel = connection->channel; + + /* Add a SecureChannel to a new connection */ + if(!channel) { + retval = UA_Server_createSecureChannel(server, connection); + if(retval != UA_STATUSCODE_GOOD) + goto error; + channel = connection->channel; + UA_assert(channel); + } + +#ifdef UA_DEBUG_DUMP_PKGS + UA_dump_hex_pkg(message->data, message->length); +#endif +#ifdef UA_DEBUG_DUMP_PKGS_FILE + UA_debug_dumpCompleteChunk(server, channel->connection, message); +#endif + + retval = UA_SecureChannel_processBuffer(channel, server, processSecureChannelMessage, message); + if(retval != UA_STATUSCODE_GOOD) { + UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_NETWORK, + "Connection %i | Processing the message failed with error %s", + (int)(connection->sockfd), UA_StatusCode_name(retval)); + goto error; + } + + return; + + error: + /* Send an ERR message and close the connection */ + error.error = retval; + error.reason = UA_STRING_NULL; + UA_Connection_sendError(connection, &error); + connection->ua_close(connection); +} + +void +UA_Server_removeConnection(UA_Server *server, UA_Connection *connection) { + UA_Connection_detachSecureChannel(connection); + connection->free(connection); +} + +/**** amalgamated original file "/src/server/ua_server_utils.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + * 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 + */ + + +const UA_DataType * +UA_Server_findDataType(UA_Server *server, const UA_NodeId *typeId) { + return UA_findDataTypeWithCustom(typeId, server->config.customDataTypes); +} + +/********************************/ +/* Information Model Operations */ +/********************************/ + +const UA_Node * +getNodeType(UA_Server *server, const UA_NodeHead *head) { + /* The reference to the parent is different for variable and variabletype */ + UA_Byte parentRefIndex; + UA_Boolean inverse; + UA_NodeClass typeNodeClass; + switch(head->nodeClass) { + case UA_NODECLASS_OBJECT: + parentRefIndex = UA_REFERENCETYPEINDEX_HASTYPEDEFINITION; + inverse = false; + typeNodeClass = UA_NODECLASS_OBJECTTYPE; + break; + case UA_NODECLASS_VARIABLE: + parentRefIndex = UA_REFERENCETYPEINDEX_HASTYPEDEFINITION; + inverse = false; + typeNodeClass = UA_NODECLASS_VARIABLETYPE; + break; + case UA_NODECLASS_OBJECTTYPE: + case UA_NODECLASS_VARIABLETYPE: + case UA_NODECLASS_REFERENCETYPE: + case UA_NODECLASS_DATATYPE: + parentRefIndex = UA_REFERENCETYPEINDEX_HASSUBTYPE; + inverse = true; + typeNodeClass = head->nodeClass; + break; + default: + return NULL; + } + + /* Return the first matching candidate */ + for(size_t i = 0; i < head->referencesSize; ++i) { + UA_NodeReferenceKind *rk = &head->references[i]; + if(rk->isInverse != inverse) + continue; + if(rk->referenceTypeIndex != parentRefIndex) + continue; + + const UA_ReferenceTarget *t = NULL; + while((t = UA_NodeReferenceKind_iterate(rk, t))) { + const UA_Node *type = UA_NODESTORE_GETFROMREF(server, t->targetId); + if(!type) + continue; + if(type->head.nodeClass == typeNodeClass) + return type; /* Don't release the node that is returned */ + UA_NODESTORE_RELEASE(server, type); + } + } + + return NULL; +} + +UA_Boolean +UA_Node_hasSubTypeOrInstances(const UA_NodeHead *head) { + for(size_t i = 0; i < head->referencesSize; ++i) { + if(head->references[i].isInverse == false && + head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASSUBTYPE) + return true; + if(head->references[i].isInverse == true && + head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASTYPEDEFINITION) + return true; + } + return false; +} + +UA_StatusCode +getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode, + UA_NodeId **typeHierarchy, size_t *typeHierarchySize) { + UA_ReferenceTypeSet reftypes_subtype = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE); + UA_ExpandedNodeId *subTypes = NULL; + size_t subTypesSize = 0; + UA_StatusCode retval = browseRecursive(server, 1, typeNode, + UA_BROWSEDIRECTION_INVERSE, + &reftypes_subtype, UA_NODECLASS_UNSPECIFIED, + false, &subTypesSize, &subTypes); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + UA_assert(subTypesSize < 1000); + + UA_ReferenceTypeSet reftypes_interface = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE); + UA_ExpandedNodeId *interfaces = NULL; + size_t interfacesSize = 0; + retval = browseRecursive(server, 1, typeNode, UA_BROWSEDIRECTION_FORWARD, + &reftypes_interface, UA_NODECLASS_UNSPECIFIED, + false, &interfacesSize, &interfaces); + if(retval != UA_STATUSCODE_GOOD) { + UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_NODEID]); + return retval; + } + + UA_assert(interfacesSize < 1000); + + UA_NodeId *hierarchy = (UA_NodeId*) + UA_malloc(sizeof(UA_NodeId) * (1 + subTypesSize + interfacesSize)); + if(!hierarchy) { + UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + UA_Array_delete(interfaces, interfacesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + retval = UA_NodeId_copy(typeNode, hierarchy); + if(retval != UA_STATUSCODE_GOOD) { + UA_free(hierarchy); + UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + UA_Array_delete(interfaces, interfacesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + for(size_t i = 0; i < subTypesSize; i++) { + hierarchy[i+1] = subTypes[i].nodeId; + UA_NodeId_init(&subTypes[i].nodeId); + } + for(size_t i = 0; i < interfacesSize; i++) { + hierarchy[i+1+subTypesSize] = interfaces[i].nodeId; + UA_NodeId_init(&interfaces[i].nodeId); + } + + *typeHierarchy = hierarchy; + *typeHierarchySize = subTypesSize + interfacesSize + 1; + + UA_assert(*typeHierarchySize < 1000); + + UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + UA_Array_delete(interfaces, interfacesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +getAllInterfaceChildNodeIds(UA_Server *server, const UA_NodeId *objectNode, + const UA_NodeId *objectTypeNode, + UA_NodeId **interfaceChildNodes, size_t *interfaceChildNodesSize) { + if(interfaceChildNodesSize == NULL || interfaceChildNodes == NULL) + return UA_STATUSCODE_BADINTERNALERROR; + *interfaceChildNodesSize = 0; + *interfaceChildNodes = NULL; + + UA_ExpandedNodeId *hasInterfaceCandidates = NULL; + size_t hasInterfaceCandidatesSize = 0; + UA_ReferenceTypeSet reftypes_subtype = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE); + + UA_StatusCode retval = browseRecursive(server, 1, objectTypeNode, UA_BROWSEDIRECTION_INVERSE, + &reftypes_subtype, UA_NODECLASS_OBJECTTYPE, + true, &hasInterfaceCandidatesSize, + &hasInterfaceCandidates); + + if (retval != UA_STATUSCODE_GOOD) + return retval; + + /* The interface could also have been added manually before calling UA_Server_addNode_finish + * This can be handled by adding the object node as a start node for the HasInterface lookup */ + UA_ExpandedNodeId *resizedHasInterfaceCandidates = + (UA_ExpandedNodeId*)UA_realloc(hasInterfaceCandidates, + (hasInterfaceCandidatesSize + 1) * sizeof(UA_ExpandedNodeId)); + + if (!resizedHasInterfaceCandidates) { + if (hasInterfaceCandidates) + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + hasInterfaceCandidates = resizedHasInterfaceCandidates; + hasInterfaceCandidatesSize += 1; + UA_ExpandedNodeId_init(&hasInterfaceCandidates[hasInterfaceCandidatesSize - 1]); + + UA_ExpandedNodeId_init(&hasInterfaceCandidates[hasInterfaceCandidatesSize - 1]); + UA_NodeId_copy(objectNode, &hasInterfaceCandidates[hasInterfaceCandidatesSize - 1].nodeId); + + size_t outputIndex = 0; + + for (size_t i = 0; i < hasInterfaceCandidatesSize; ++i) { + UA_ReferenceTypeSet reftypes_interface = + UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE); + UA_ExpandedNodeId *interfaceChildren = NULL; + size_t interfacesChildrenSize = 0; + retval = browseRecursive(server, 1, &hasInterfaceCandidates[i].nodeId, + UA_BROWSEDIRECTION_FORWARD, + &reftypes_interface, UA_NODECLASS_OBJECTTYPE, + false, &interfacesChildrenSize, &interfaceChildren); + if(retval != UA_STATUSCODE_GOOD) { + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + if (*interfaceChildNodesSize) { + UA_Array_delete(*interfaceChildNodes, *interfaceChildNodesSize, + &UA_TYPES[UA_TYPES_NODEID]); + *interfaceChildNodesSize = 0; + } + return retval; + } + + UA_assert(interfacesChildrenSize < 1000); + + if (interfacesChildrenSize == 0) { + continue; + } + + if (!*interfaceChildNodes) { + *interfaceChildNodes = (UA_NodeId*) + UA_calloc(interfacesChildrenSize, sizeof(UA_NodeId)); + *interfaceChildNodesSize = interfacesChildrenSize; + + if(!*interfaceChildNodes) { + UA_Array_delete(interfaceChildren, interfacesChildrenSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + } else { + UA_NodeId *resizedInterfaceChildNodes = + (UA_NodeId*)UA_realloc(*interfaceChildNodes, + ((*interfaceChildNodesSize + interfacesChildrenSize) * sizeof(UA_NodeId))); + + if (!resizedInterfaceChildNodes) { + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + UA_Array_delete(interfaceChildren, interfacesChildrenSize, + &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + const size_t oldSize = *interfaceChildNodesSize; + *interfaceChildNodesSize += interfacesChildrenSize; + *interfaceChildNodes = resizedInterfaceChildNodes; + + for (size_t j = oldSize; j < *interfaceChildNodesSize; ++j) + UA_NodeId_init(&(*interfaceChildNodes)[j]); + } + + for(size_t j = 0; j < interfacesChildrenSize; j++) { + (*interfaceChildNodes)[outputIndex++] = interfaceChildren[j].nodeId; + } + + UA_assert(*interfaceChildNodesSize < 1000); + UA_Array_delete(interfaceChildren, interfacesChildrenSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + } + + UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]); + + return UA_STATUSCODE_GOOD; +} + +/* For mulithreading: make a copy of the node, edit and replace. + * For singlethreading: edit the original */ +UA_StatusCode +UA_Server_editNode(UA_Server *server, UA_Session *session, + const UA_NodeId *nodeId, UA_EditNodeCallback callback, + void *data) { +#ifndef UA_ENABLE_IMMUTABLE_NODES + /* Get the node and process it in-situ */ + 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 { + /* Get an editable copy of the node */ + UA_Node *node; + retval = UA_NODESTORE_GETCOPY(server, nodeId, &node); + if(retval != UA_STATUSCODE_GOOD) + return retval; + + /* Run the operation on the copy */ + retval = callback(server, session, node, data); + if(retval != UA_STATUSCODE_GOOD) { + UA_NODESTORE_DELETE(server, node); + return retval; + } + + /* Replace the node */ + retval = UA_NODESTORE_REPLACE(server, node); + } while(retval != UA_STATUSCODE_GOOD); + return retval; +#endif +} + +UA_StatusCode +UA_Server_processServiceOperations(UA_Server *server, UA_Session *session, + UA_ServiceOperation operationCallback, + const 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; +} + +/* A few global NodeId definitions */ +const UA_NodeId subtypeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}}; +const UA_NodeId hierarchicalReferences = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HIERARCHICALREFERENCES}}; + +/*********************************/ +/* 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 "/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) Fraunhofer IOSB (Author: Julius Pfrommer) + * Copyright 2017 (c) Stefan Profanter, fortiss GmbH + * Copyright 2017 (c) HMS Industrial Networks AB (Author: Jonas Green) + */ + + + +#ifdef UA_ENABLE_DISCOVERY + +UA_StatusCode +register_server_with_discovery_server(UA_Server *server, + void *pClient, + const UA_Boolean isUnregister, + const char* semaphoreFilePath) { + UA_Client *client = (UA_Client *) pClient; + + /* 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; + + /* Mirror the discovery urls from the server config and the network layers */ + size_t config_discurls = server->config.applicationDescription.discoveryUrlsSize; + size_t nl_discurls = server->config.networkLayersSize; + size_t total_discurls = config_discurls + nl_discurls; + request.server.discoveryUrls = (UA_String*) + UA_Array_new(total_discurls, &UA_TYPES[UA_TYPES_STRING]); + if(!request.server.discoveryUrls) + return UA_STATUSCODE_BADOUTOFMEMORY; + + for(size_t i = 0; i < config_discurls; ++i) + request.server.discoveryUrls[i] = server->config.applicationDescription.discoveryUrls[i]; + /* TODO: Add nl only if discoveryUrl not already present */ + for(size_t i = 0; i < nl_discurls; ++i) { + UA_ServerNetworkLayer *nl = &server->config.networkLayers[i]; + request.server.discoveryUrls[config_discurls + i] = nl->discoveryUrl; + } + request.server.discoveryUrlsSize = total_discurls; + +#ifdef UA_ENABLE_DISCOVERY_MULTICAST + request.discoveryConfigurationSize = 1; + request.discoveryConfiguration = UA_ExtensionObject_new(); + // Set to NODELETE so that we can just use a pointer to the mdns config + UA_ExtensionObject_setValueNoDelete(request.discoveryConfiguration, + &server->config.mdnsConfig, + &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION]); +#endif + + // First try with RegisterServer2, if that isn't implemented, use RegisterServer + 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_clear(&response); + UA_Array_delete(request.discoveryConfiguration, + request.discoveryConfigurationSize, + &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]); + if(total_discurls > 0) + UA_free(request.server.discoveryUrls); + + 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_clear(&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)); + } + + return serviceResult; +} + +UA_StatusCode +UA_Server_register_discovery(UA_Server *server, UA_Client *client, + const char* semaphoreFilePath) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = register_server_with_discovery_server(server, client, + false, semaphoreFilePath); + UA_UNLOCK(&server->serviceMutex); + return retval; +} + +UA_StatusCode +UA_Server_unregister_discovery(UA_Server *server, UA_Client *client) { + UA_LOCK(&server->serviceMutex); + UA_StatusCode retval = register_server_with_discovery_server(server, client, + true, NULL); + UA_UNLOCK(&server->serviceMutex); + return retval; +} + +#endif /* UA_ENABLE_DISCOVERY */ + +/**** amalgamated original file "/src/server/ua_server_async.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright 2019 (c) Fraunhofer IOSB (Author: Klaus Schick) + * Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer) + */ + + +#if UA_MULTITHREADING >= 100 + +static void +UA_AsyncOperation_delete(UA_AsyncOperation *ar) { + UA_CallMethodRequest_clear(&ar->request); + UA_CallMethodResult_clear(&ar->response); + UA_free(ar); +} + +static UA_StatusCode +UA_AsyncManager_sendAsyncResponse(UA_AsyncManager *am, UA_Server *server, + UA_AsyncResponse *ar) { + /* Get the session */ + UA_StatusCode res = UA_STATUSCODE_GOOD; + UA_LOCK(&server->serviceMutex); + UA_Session* session = UA_Server_getSessionById(server, &ar->sessionId); + UA_UNLOCK(&server->serviceMutex); + UA_SecureChannel* channel = NULL; + UA_ResponseHeader *responseHeader = NULL; + if(!session) { + res = UA_STATUSCODE_BADSESSIONIDINVALID; + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_InsertMethodResponse: Session is gone"); + goto clean_up; + } + + /* Check the channel */ + channel = session->header.channel; + if(!channel) { + res = UA_STATUSCODE_BADSECURECHANNELCLOSED; + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_InsertMethodResponse: Channel is gone"); + goto clean_up; + } + + /* Okay, here we go, send the UA_CallResponse */ + responseHeader = (UA_ResponseHeader*) + &ar->response.callResponse.responseHeader; + responseHeader->requestHandle = ar->requestHandle; + res = sendResponse(server, session, channel, ar->requestId, + (UA_Response*)&ar->response, &UA_TYPES[UA_TYPES_CALLRESPONSE]); + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_SendResponse: Response for Req# %" PRIu32 " sent", ar->requestId); + + clean_up: + /* Remove from the AsyncManager */ + UA_AsyncManager_removeAsyncResponse(&server->asyncManager, ar); + return res; +} + +/* Integrate operation result in the AsyncResponse and send out the response if + * it is ready. */ +static void +integrateOperationResult(UA_AsyncManager *am, UA_Server *server, + UA_AsyncOperation *ao) { + /* Grab the open request, so we can continue to construct the response */ + UA_AsyncResponse *ar = ao->parent; + + /* Reduce the number of open results */ + ar->opCountdown -= 1; + + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Return result in the server thread with %" PRIu32 " remaining", + ar->opCountdown); + + /* Move the UA_CallMethodResult to UA_CallResponse */ + ar->response.callResponse.results[ao->index] = ao->response; + UA_CallMethodResult_init(&ao->response); + + /* Are we done with all operations? */ + if(ar->opCountdown == 0) + UA_AsyncManager_sendAsyncResponse(am, server, ar); +} + +/* Process all operations in the result queue -> move content over to the + * AsyncResponse. This is only done by the server thread. */ +static void +processAsyncResults(UA_Server *server, void *data) { + UA_AsyncManager *am = &server->asyncManager; + while(true) { + UA_LOCK(&am->queueLock); + UA_AsyncOperation *ao = TAILQ_FIRST(&am->resultQueue); + if(ao) + TAILQ_REMOVE(&am->resultQueue, ao, pointers); + UA_UNLOCK(&am->queueLock); + if(!ao) + break; + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_CallMethodResponse: Got Response: OKAY"); + integrateOperationResult(am, server, ao); + UA_AsyncOperation_delete(ao); + am->opsCount--; + } +} + +/* Check if any operations have timed out */ +static void +checkTimeouts(UA_Server *server, void *_) { + /* Timeouts are not configured */ + if(server->config.asyncOperationTimeout <= 0.0) + return; + + UA_AsyncManager *am = &server->asyncManager; + const UA_DateTime tNow = UA_DateTime_now(); + + UA_LOCK(&am->queueLock); + + /* Loop over the queue of dispatched ops */ + UA_AsyncOperation *op = NULL, *op_tmp = NULL; + TAILQ_FOREACH_SAFE(op, &am->dispatchedQueue, pointers, op_tmp) { + /* The timeout has not passed. Also for all elements following in the queue. */ + if(tNow <= op->parent->timeout) + break; + + /* Mark as timed out and put it into the result queue */ + op->response.statusCode = UA_STATUSCODE_BADTIMEOUT; + TAILQ_REMOVE(&am->dispatchedQueue, op, pointers); + TAILQ_INSERT_TAIL(&am->resultQueue, op, pointers); + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Operation was removed due to a timeout"); + } + + /* Loop over the queue of new ops */ + TAILQ_FOREACH_SAFE(op, &am->newQueue, pointers, op_tmp) { + /* The timeout has not passed. Also for all elements following in the queue. */ + if(tNow <= op->parent->timeout) + break; + + /* Mark as timed out and put it into the result queue */ + op->response.statusCode = UA_STATUSCODE_BADTIMEOUT; + TAILQ_REMOVE(&am->newQueue, op, pointers); + TAILQ_INSERT_TAIL(&am->resultQueue, op, pointers); + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Operation was removed due to a timeout"); + } + + UA_UNLOCK(&am->queueLock); + + /* Integrate async results and send out complete responses */ + processAsyncResults(server, NULL); +} + +void +UA_AsyncManager_init(UA_AsyncManager *am, UA_Server *server) { + memset(am, 0, sizeof(UA_AsyncManager)); + TAILQ_INIT(&am->asyncResponses); + TAILQ_INIT(&am->newQueue); + TAILQ_INIT(&am->dispatchedQueue); + TAILQ_INIT(&am->resultQueue); + UA_LOCK_INIT(&am->queueLock); + + /* Add a regular callback for cleanup and sending finished responses at a + * 100s interval. */ + UA_Server_addRepeatedCallback(server, (UA_ServerCallback)checkTimeouts, + NULL, 100.0, &am->checkTimeoutCallbackId); +} + +void +UA_AsyncManager_clear(UA_AsyncManager *am, UA_Server *server) { + removeCallback(server, am->checkTimeoutCallbackId); + + UA_AsyncOperation *ar; + + /* Clean up queues */ + UA_LOCK(&am->queueLock); + while((ar = TAILQ_FIRST(&am->newQueue))) { + TAILQ_REMOVE(&am->resultQueue, ar, pointers); + UA_AsyncOperation_delete(ar); + } + while((ar = TAILQ_FIRST(&am->dispatchedQueue))) { + TAILQ_REMOVE(&am->resultQueue, ar, pointers); + UA_AsyncOperation_delete(ar); + } + while((ar = TAILQ_FIRST(&am->resultQueue))) { + TAILQ_REMOVE(&am->resultQueue, ar, pointers); + UA_AsyncOperation_delete(ar); + } + UA_UNLOCK(&am->queueLock); + + /* Remove responses */ + UA_AsyncResponse *current, *temp; + TAILQ_FOREACH_SAFE(current, &am->asyncResponses, pointers, temp) { + UA_AsyncManager_removeAsyncResponse(am, current); + } + + /* Delete all locks */ + UA_LOCK_DESTROY(&am->queueLock); +} + +UA_StatusCode +UA_AsyncManager_createAsyncResponse(UA_AsyncManager *am, UA_Server *server, + const UA_NodeId *sessionId, + const UA_UInt32 requestId, const UA_UInt32 requestHandle, + const UA_AsyncOperationType operationType, + UA_AsyncResponse **outAr) { + UA_AsyncResponse *newentry = (UA_AsyncResponse*)UA_calloc(1, sizeof(UA_AsyncResponse)); + if(!newentry) + return UA_STATUSCODE_BADOUTOFMEMORY; + + UA_StatusCode res = UA_NodeId_copy(sessionId, &newentry->sessionId); + if(res != UA_STATUSCODE_GOOD) { + UA_free(newentry); + return res; + } + + am->asyncResponsesCount += 1; + newentry->requestId = requestId; + newentry->requestHandle = requestHandle; + newentry->timeout = UA_DateTime_now(); + if(server->config.asyncOperationTimeout > 0.0) + newentry->timeout += (UA_DateTime) + (server->config.asyncOperationTimeout * (UA_DateTime)UA_DATETIME_MSEC); + TAILQ_INSERT_TAIL(&am->asyncResponses, newentry, pointers); + + *outAr = newentry; + return UA_STATUSCODE_GOOD; +} + +/* Remove entry and free all allocated data */ +void +UA_AsyncManager_removeAsyncResponse(UA_AsyncManager *am, UA_AsyncResponse *ar) { + TAILQ_REMOVE(&am->asyncResponses, ar, pointers); + am->asyncResponsesCount -= 1; + UA_CallResponse_clear(&ar->response.callResponse); + UA_NodeId_clear(&ar->sessionId); + UA_free(ar); +} + +/* Enqueue next MethodRequest */ +UA_StatusCode +UA_AsyncManager_createAsyncOp(UA_AsyncManager *am, UA_Server *server, + UA_AsyncResponse *ar, size_t opIndex, + const UA_CallMethodRequest *opRequest) { + if(server->config.maxAsyncOperationQueueSize != 0 && + am->opsCount >= server->config.maxAsyncOperationQueueSize) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_SetNextAsyncMethod: Queue exceeds limit (%d).", + (int unsigned)server->config.maxAsyncOperationQueueSize); + return UA_STATUSCODE_BADUNEXPECTEDERROR; + } + + UA_AsyncOperation *ao = (UA_AsyncOperation*)UA_calloc(1, sizeof(UA_AsyncOperation)); + if(!ao) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_SetNextAsyncMethod: Mem alloc failed."); + return UA_STATUSCODE_BADOUTOFMEMORY; + } + + UA_StatusCode result = UA_CallMethodRequest_copy(opRequest, &ao->request); + if(result != UA_STATUSCODE_GOOD) { + UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_SetAsyncMethodResult: UA_CallMethodRequest_copy failed."); + UA_free(ao); + return result; + } + + UA_CallMethodResult_init(&ao->response); + ao->index = opIndex; + ao->parent = ar; + + UA_LOCK(&am->queueLock); + TAILQ_INSERT_TAIL(&am->newQueue, ao, pointers); + am->opsCount++; + ar->opCountdown++; + UA_UNLOCK(&am->queueLock); + + if(server->config.asyncOperationNotifyCallback) + server->config.asyncOperationNotifyCallback(server); + + return UA_STATUSCODE_GOOD; +} + +/* Get and remove next Method Call Request */ +UA_Boolean +UA_Server_getAsyncOperationNonBlocking(UA_Server *server, UA_AsyncOperationType *type, + const UA_AsyncOperationRequest **request, + void **context, UA_DateTime *timeout) { + UA_AsyncManager *am = &server->asyncManager; + + UA_Boolean bRV = false; + *type = UA_ASYNCOPERATIONTYPE_INVALID; + UA_LOCK(&am->queueLock); + UA_AsyncOperation *ao = TAILQ_FIRST(&am->newQueue); + if(ao) { + TAILQ_REMOVE(&am->newQueue, ao, pointers); + TAILQ_INSERT_TAIL(&am->dispatchedQueue, ao, pointers); + *type = UA_ASYNCOPERATIONTYPE_CALL; + *request = (UA_AsyncOperationRequest*)&ao->request; + *context = (void*)ao; + if(timeout) + *timeout = ao->parent->timeout; + bRV = true; + } + UA_UNLOCK(&am->queueLock); + + return bRV; +} + +UA_Boolean +UA_Server_getAsyncOperation(UA_Server *server, UA_AsyncOperationType *type, + const UA_AsyncOperationRequest **request, + void **context) { + return UA_Server_getAsyncOperationNonBlocking(server, type, request, context, NULL); +} + +/* Worker submits Method Call Response */ +void +UA_Server_setAsyncOperationResult(UA_Server *server, + const UA_AsyncOperationResponse *response, + void *context) { + UA_AsyncManager *am = &server->asyncManager; + + UA_AsyncOperation *ao = (UA_AsyncOperation*)context; + if(!ao) { + /* Something went wrong. Not a good AsyncOp. */ + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_SetAsyncMethodResult: Invalid context"); + return; + } + + UA_LOCK(&am->queueLock); + + /* See if the operation is still in the dispatched queue. Otherwise it has + * been removed due to a timeout. + * + * TODO: Add a tree-structure for the dispatch queue. The linear lookup does + * not scale. */ + UA_Boolean found = false; + UA_AsyncOperation *op = NULL; + TAILQ_FOREACH(op, &am->dispatchedQueue, pointers) { + if(op == ao) { + found = true; + break; + } + } + + if(!found) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_SetAsyncMethodResult: The operation has timed out"); + UA_UNLOCK(&am->queueLock); + return; + } + + /* Copy the result into the internal AsyncOperation */ + UA_StatusCode result = + UA_CallMethodResult_copy(&response->callMethodResult, &ao->response); + if(result != UA_STATUSCODE_GOOD) { + UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER, + "UA_Server_SetAsyncMethodResult: UA_CallMethodResult_copy failed."); + ao->response.statusCode = UA_STATUSCODE_BADOUTOFMEMORY; + } + + /* Move to the result queue */ + TAILQ_REMOVE(&am->dispatchedQueue, ao, pointers); + TAILQ_INSERT_TAIL(&am->resultQueue, ao, pointers); + + UA_UNLOCK(&am->queueLock); + + UA_LOG_DEBUG(&server->config.logger, UA_LOGCATEGORY_SERVER, + "Set the result from the worker thread"); +} + +/******************/ +/* Server Methods */ +/******************/ + +static UA_StatusCode +setMethodNodeAsync(UA_Server *server, UA_Session *session, + UA_Node *node, UA_Boolean *isAsync) { + if(node->head.nodeClass != UA_NODECLASS_METHOD) + return UA_STATUSCODE_BADNODECLASSINVALID; + node->methodNode.async = *isAsync; + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_Server_setMethodNodeAsync(UA_Server *server, const UA_NodeId id, + UA_Boolean isAsync) { + return UA_Server_editNode(server, &server->adminSession, &id, + (UA_EditNodeCallback)setMethodNodeAsync, &isAsync); +} + +UA_StatusCode +UA_Server_processServiceOperationsAsync(UA_Server *server, UA_Session *session, + UA_UInt32 requestId, UA_UInt32 requestHandle, + UA_AsyncServiceOperation operationCallback, + const size_t *requestOperations, + const UA_DataType *requestOperationsType, + size_t *responseOperations, + const UA_DataType *responseOperationsType, + UA_AsyncResponse **ar) { + size_t ops = *requestOperations; + if(ops == 0) + return UA_STATUSCODE_BADNOTHINGTODO; + + /* Allocate the response array. 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; + + /* Finish / dispatch the operations. This may allocate a new AsyncResponse internally */ + uintptr_t respOp = (uintptr_t)*respPos; + uintptr_t reqOp = *(uintptr_t*)((uintptr_t)requestOperations + sizeof(size_t)); + for(size_t i = 0; i < ops; i++) { + operationCallback(server, session, requestId, requestHandle, + i, (void*)reqOp, (void*)respOp, ar); + reqOp += requestOperationsType->memSize; + respOp += responseOperationsType->memSize; + } + + return UA_STATUSCODE_GOOD; +} + +#endif + +/**** amalgamated original file "/src/pubsub/ua_pubsub_networkmessage.c" ****/ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2017 - 2018 Fraunhofer IOSB (Author: Tino Bischoff) + * Copyright (c) 2019 Fraunhofer IOSB (Author: Andreas Ebner) + */ + + + +#ifdef UA_ENABLE_PUBSUB /* conditional compilation */ + +const UA_Byte NM_VERSION_MASK = 15; +const UA_Byte NM_PUBLISHER_ID_ENABLED_MASK = 16; +const UA_Byte NM_GROUP_HEADER_ENABLED_MASK = 32; +const UA_Byte NM_PAYLOAD_HEADER_ENABLED_MASK = 64; +const UA_Byte NM_EXTENDEDFLAGS1_ENABLED_MASK = 128; +const UA_Byte NM_PUBLISHER_ID_MASK = 7; +const UA_Byte NM_DATASET_CLASSID_ENABLED_MASK = 8; +const UA_Byte NM_SECURITY_ENABLED_MASK = 16; +const UA_Byte NM_TIMESTAMP_ENABLED_MASK = 32; +const UA_Byte NM_PICOSECONDS_ENABLED_MASK = 64; +const UA_Byte NM_EXTENDEDFLAGS2_ENABLED_MASK = 128; +const UA_Byte NM_NETWORK_MSG_TYPE_MASK = 28; +const UA_Byte NM_CHUNK_MESSAGE_MASK = 1; +const UA_Byte NM_PROMOTEDFIELDS_ENABLED_MASK = 2; +const UA_Byte GROUP_HEADER_WRITER_GROUPID_ENABLED = 1; +const UA_Byte GROUP_HEADER_GROUP_VERSION_ENABLED = 2; +const UA_Byte GROUP_HEADER_NM_NUMBER_ENABLED = 4; +const UA_Byte GROUP_HEADER_SEQUENCE_NUMBER_ENABLED = 8; +const UA_Byte SECURITY_HEADER_NM_SIGNED = 1; +const UA_Byte SECURITY_HEADER_NM_ENCRYPTED = 2; +const UA_Byte SECURITY_HEADER_SEC_FOOTER_ENABLED = 4; +const UA_Byte SECURITY_HEADER_FORCE_KEY_RESET = 8; +const UA_Byte DS_MESSAGEHEADER_DS_MSG_VALID = 1; +const UA_Byte DS_MESSAGEHEADER_FIELD_ENCODING_MASK = 6; +const UA_Byte DS_MESSAGEHEADER_SEQ_NR_ENABLED_MASK = 8; +const UA_Byte DS_MESSAGEHEADER_STATUS_ENABLED_MASK = 16; +const UA_Byte DS_MESSAGEHEADER_CONFIGMAJORVERSION_ENABLED_MASK = 32; +const UA_Byte DS_MESSAGEHEADER_CONFIGMINORVERSION_ENABLED_MASK = 64; +const UA_Byte DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK = 128; +const UA_Byte DS_MESSAGEHEADER_DS_MESSAGE_TYPE_MASK = 15; +const UA_Byte DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK = 16; +const UA_Byte DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK = 32; +const UA_Byte NM_SHIFT_LEN = 2; +const UA_Byte DS_MH_SHIFT_LEN = 1; + +static UA_Boolean UA_NetworkMessage_ExtendedFlags1Enabled(const UA_NetworkMessage* src); +static UA_Boolean UA_NetworkMessage_ExtendedFlags2Enabled(const UA_NetworkMessage* src); +static UA_Boolean UA_DataSetMessageHeader_DataSetFlags2Enabled(const UA_DataSetMessageHeader* src); + +UA_StatusCode +UA_NetworkMessage_updateBufferedMessage(UA_NetworkMessageOffsetBuffer *buffer){ + UA_StatusCode rv = UA_STATUSCODE_GOOD; + for(size_t i = 0; i < buffer->offsetsSize; ++i) { + UA_NetworkMessageOffset *nmo = &buffer->offsets[i]; + const UA_Byte *bufEnd = &buffer->buffer.data[buffer->buffer.length]; + UA_Byte *bufPos = &buffer->buffer.data[nmo->offset]; + switch(nmo->contentType) { + case UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER: + case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER: + rv = UA_UInt16_encodeBinary((UA_UInt16 *)nmo->offsetData.value.value->value.data, &bufPos, bufEnd); + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE: + rv = UA_DataValue_encodeBinary(nmo->offsetData.value.value, + &bufPos, bufEnd); + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT: + rv = UA_Variant_encodeBinary(&nmo->offsetData.value.value->value, + &bufPos, bufEnd); + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW: + rv = UA_encodeBinaryInternal(nmo->offsetData.value.value->value.data, + nmo->offsetData.value.value->value.type, + &bufPos, &bufEnd, NULL, NULL); + break; + case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING: + break; + default: + return UA_STATUSCODE_BADNOTSUPPORTED; + } + } + return rv; +} + +UA_StatusCode +UA_NetworkMessage_updateBufferedNwMessage(UA_NetworkMessageOffsetBuffer *buffer, + const UA_ByteString *src, size_t *bufferPosition){ + UA_StatusCode rv = UA_STATUSCODE_GOOD; + size_t payloadCounter = 0; + size_t offset = 0; + UA_DataSetMessage* dsm = buffer->nm->payload.dataSetPayload.dataSetMessages; //Considering one DSM in RT TODO: Clarify multiple DSM + UA_DataSetMessageHeader header; + size_t smallestRawOffset = UA_UINT32_MAX; + + for (size_t i = 0; i < buffer->offsetsSize; ++i) { + offset = buffer->offsets[i].offset + *bufferPosition; + switch (buffer->offsets[i].contentType) { + case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING: + rv = UA_DataSetMessageHeader_decodeBinary(src, &offset, &header); + if(rv != UA_STATUSCODE_GOOD) + return rv; + break; + case UA_PUBSUB_OFFSETTYPE_PUBLISHERID: + switch (buffer->nm->publisherIdType) { + case UA_PUBLISHERDATATYPE_BYTE: + rv = UA_Byte_decodeBinary(src, &offset, &(buffer->nm->publisherId.publisherIdByte)); + break; + case UA_PUBLISHERDATATYPE_UINT16: + rv = UA_UInt16_decodeBinary(src, &offset, &(buffer->nm->publisherId.publisherIdUInt16)); + break; + case UA_PUBLISHERDATATYPE_UINT32: + rv = UA_UInt32_decodeBinary(src, &offset, &(buffer->nm->publisherId.publisherIdUInt32)); + break; + case UA_PUBLISHERDATATYPE_UINT64: + rv = UA_UInt64_decodeBinary(src, &offset, &(buffer->nm->publisherId.publisherIdUInt64)); + break; + default: + return UA_STATUSCODE_BADNOTSUPPORTED; + } + break; + case UA_PUBSUB_OFFSETTYPE_WRITERGROUPID: + rv = UA_UInt16_decodeBinary(src, &offset, &buffer->nm->groupHeader.writerGroupId); + UA_CHECK_STATUS(rv, return rv); + break; + case UA_PUBSUB_OFFSETTYPE_DATASETWRITERID: + rv = UA_UInt16_decodeBinary(src, &offset, + &buffer->nm->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0]); /* TODO */ + UA_CHECK_STATUS(rv, return rv); + break; + case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER: + rv = UA_UInt16_decodeBinary(src, &offset, &buffer->nm->groupHeader.sequenceNumber); + UA_CHECK_STATUS(rv, return rv); + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE: + rv = UA_DataValue_decodeBinary(src, &offset, + &(dsm->data.keyFrameData.dataSetFields[payloadCounter])); + UA_CHECK_STATUS(rv, return rv); + payloadCounter++; + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT: + rv = UA_Variant_decodeBinary(src, &offset, + &dsm->data.keyFrameData.dataSetFields[payloadCounter].value); + UA_CHECK_STATUS(rv, return rv); + dsm->data.keyFrameData.dataSetFields[payloadCounter].hasValue = true; + payloadCounter++; + break; + case UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW: + /* We need only the start address of the raw fields */ + if (smallestRawOffset > offset){ + smallestRawOffset = offset; + dsm->data.keyFrameData.rawFields.data = &src->data[offset]; + dsm->data.keyFrameData.rawFields.length = buffer->rawMessageLength; + } + payloadCounter++; + break; + default: + return UA_STATUSCODE_BADNOTSUPPORTED; + } + } + //check if the frame is of type "raw" payload + if(smallestRawOffset != UA_UINT32_MAX){ + *bufferPosition = smallestRawOffset + buffer->rawMessageLength; + } else { + *bufferPosition = offset; + } + + return rv; +} + +static +UA_StatusCode +UA_NetworkMessageHeader_encodeBinary(const UA_NetworkMessage *src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + /* UADPVersion + UADP Flags */ + UA_Byte v = src->version; + if(src->publisherIdEnabled) + v |= NM_PUBLISHER_ID_ENABLED_MASK; + + if(src->groupHeaderEnabled) + v |= NM_GROUP_HEADER_ENABLED_MASK; + + if(src->payloadHeaderEnabled) + v |= NM_PAYLOAD_HEADER_ENABLED_MASK; + + if(UA_NetworkMessage_ExtendedFlags1Enabled(src)) + v |= NM_EXTENDEDFLAGS1_ENABLED_MASK; + + UA_StatusCode rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // ExtendedFlags1 + if(UA_NetworkMessage_ExtendedFlags1Enabled(src)) { + v = (UA_Byte)src->publisherIdType; + + if(src->dataSetClassIdEnabled) + v |= NM_DATASET_CLASSID_ENABLED_MASK; + + if(src->securityEnabled) + v |= NM_SECURITY_ENABLED_MASK; + + if(src->timestampEnabled) + v |= NM_TIMESTAMP_ENABLED_MASK; + + if(src->picosecondsEnabled) + v |= NM_PICOSECONDS_ENABLED_MASK; + + if(UA_NetworkMessage_ExtendedFlags2Enabled(src)) + v |= NM_EXTENDEDFLAGS2_ENABLED_MASK; + + rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + // ExtendedFlags2 + if(UA_NetworkMessage_ExtendedFlags2Enabled(src)) { + v = (UA_Byte)src->networkMessageType; + // shift left 2 bit + v = (UA_Byte) (v << NM_SHIFT_LEN); + + if(src->chunkMessage) + v |= NM_CHUNK_MESSAGE_MASK; + + if(src->promotedFieldsEnabled) + v |= NM_PROMOTEDFIELDS_ENABLED_MASK; + + rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + } + + // PublisherId + if(src->publisherIdEnabled) { + switch (src->publisherIdType) { + case UA_PUBLISHERDATATYPE_BYTE: + rv = UA_Byte_encodeBinary(&(src->publisherId.publisherIdByte), bufPos, bufEnd); + break; + + case UA_PUBLISHERDATATYPE_UINT16: + rv = UA_UInt16_encodeBinary(&(src->publisherId.publisherIdUInt16), bufPos, bufEnd); + break; + + case UA_PUBLISHERDATATYPE_UINT32: + rv = UA_UInt32_encodeBinary(&(src->publisherId.publisherIdUInt32), bufPos, bufEnd); + break; + + case UA_PUBLISHERDATATYPE_UINT64: + rv = UA_UInt64_encodeBinary(&(src->publisherId.publisherIdUInt64), bufPos, bufEnd); + break; + + case UA_PUBLISHERDATATYPE_STRING: + rv = UA_String_encodeBinary(&(src->publisherId.publisherIdString), bufPos, bufEnd); + break; + + default: + rv = UA_STATUSCODE_BADINTERNALERROR; + break; + } + UA_CHECK_STATUS(rv, return rv); + } + + // DataSetClassId + if(src->dataSetClassIdEnabled) { + rv = UA_Guid_encodeBinary(&(src->dataSetClassId), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + +static +UA_StatusCode +UA_GroupHeader_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + UA_Byte v = 0; + + if(src->groupHeader.writerGroupIdEnabled) + v |= GROUP_HEADER_WRITER_GROUPID_ENABLED; + + if(src->groupHeader.groupVersionEnabled) + v |= GROUP_HEADER_GROUP_VERSION_ENABLED; + + if(src->groupHeader.networkMessageNumberEnabled) + v |= GROUP_HEADER_NM_NUMBER_ENABLED; + + if(src->groupHeader.sequenceNumberEnabled) + v |= GROUP_HEADER_SEQUENCE_NUMBER_ENABLED; + + UA_StatusCode rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + if(src->groupHeader.writerGroupIdEnabled) { + rv = UA_UInt16_encodeBinary(&(src->groupHeader.writerGroupId), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + if(src->groupHeader.groupVersionEnabled) { + rv = UA_UInt32_encodeBinary(&(src->groupHeader.groupVersion), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + if(src->groupHeader.networkMessageNumberEnabled) { + rv = UA_UInt16_encodeBinary(&(src->groupHeader.networkMessageNumber), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + if(src->groupHeader.sequenceNumberEnabled) { + rv = UA_UInt16_encodeBinary(&(src->groupHeader.sequenceNumber), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + +static +UA_StatusCode +UA_PayloadHeader_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET) + return UA_STATUSCODE_BADNOTIMPLEMENTED; + + UA_StatusCode rv = UA_Byte_encodeBinary(&(src->payloadHeader.dataSetPayloadHeader.count), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + if(src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds == NULL) + return UA_STATUSCODE_BADENCODINGERROR; + + for(UA_Byte i = 0; i < src->payloadHeader.dataSetPayloadHeader.count; i++) { + rv = UA_UInt16_encodeBinary(&(src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[i]), + bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + +static +UA_StatusCode +UA_ExtendedNetworkMessageHeader_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + UA_StatusCode rv = UA_STATUSCODE_GOOD; + // Timestamp + if(src->timestampEnabled) + rv = UA_DateTime_encodeBinary(&(src->timestamp), bufPos, bufEnd); + + UA_CHECK_STATUS(rv, return rv); + // Picoseconds + if(src->picosecondsEnabled) + rv = UA_UInt16_encodeBinary(&(src->picoseconds), bufPos, bufEnd); + + UA_CHECK_STATUS(rv, return rv); + // PromotedFields + if(src->promotedFieldsEnabled) { + /* Size (calculate & encode) */ + UA_UInt16 pfSize = 0; + for(UA_UInt16 i = 0; i < src->promotedFieldsSize; i++) + pfSize = (UA_UInt16) (pfSize + UA_Variant_calcSizeBinary(&src->promotedFields[i])); + rv |= UA_UInt16_encodeBinary(&pfSize, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + for (UA_UInt16 i = 0; i < src->promotedFieldsSize; i++) + rv |= UA_Variant_encodeBinary(&(src->promotedFields[i]), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + +static +UA_StatusCode +UA_SecurityHeader_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + // SecurityFlags + UA_Byte v = 0; + if(src->securityHeader.networkMessageSigned) + v |= SECURITY_HEADER_NM_SIGNED; + + if(src->securityHeader.networkMessageEncrypted) + v |= SECURITY_HEADER_NM_ENCRYPTED; + + if(src->securityHeader.securityFooterEnabled) + v |= SECURITY_HEADER_SEC_FOOTER_ENABLED; + + if(src->securityHeader.forceKeyReset) + v |= SECURITY_HEADER_FORCE_KEY_RESET; + + UA_StatusCode rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // SecurityTokenId + rv = UA_UInt32_encodeBinary(&src->securityHeader.securityTokenId, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // NonceLength + UA_Byte nonceLength = (UA_Byte)src->securityHeader.messageNonce.length; + rv = UA_Byte_encodeBinary(&nonceLength, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // MessageNonce + for (size_t i = 0; i < src->securityHeader.messageNonce.length; i++) { + rv = UA_Byte_encodeBinary(&src->securityHeader.messageNonce.data[i], + bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + // SecurityFooterSize + if(src->securityHeader.securityFooterEnabled) { + rv = UA_UInt16_encodeBinary(&src->securityHeader.securityFooterSize, + bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_NetworkMessage_encodeHeaders(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + UA_StatusCode rv = UA_NetworkMessageHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // Group Header + if(src->groupHeaderEnabled) { + rv = UA_GroupHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + // Payload Header + if(src->payloadHeaderEnabled) { + rv = UA_PayloadHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + // Extended Network Message Header + rv = UA_ExtendedNetworkMessageHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + // SecurityHeader + if(src->securityEnabled) { + rv = UA_SecurityHeader_encodeBinary(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + + +UA_StatusCode +UA_NetworkMessage_encodePayload(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + UA_StatusCode rv; + + // Payload + if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET) + return UA_STATUSCODE_BADNOTIMPLEMENTED; + + UA_Byte count = 1; + + if(src->payloadHeaderEnabled) { + count = src->payloadHeader.dataSetPayloadHeader.count; + if(count > 1) { + for (UA_Byte i = 0; i < count; i++) { + // initially calculate the size, if not specified + UA_UInt16 sz = 0; + if((src->payload.dataSetPayload.sizes != NULL) && + (src->payload.dataSetPayload.sizes[i] != 0)) { + sz = src->payload.dataSetPayload.sizes[i]; + } else { + sz = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&src->payload.dataSetPayload.dataSetMessages[i], + NULL, 0); + } + + rv = UA_UInt16_encodeBinary(&sz, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + } + } + + for(UA_Byte i = 0; i < count; i++) { + rv = UA_DataSetMessage_encodeBinary(&(src->payload.dataSetPayload.dataSetMessages[i]), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_NetworkMessage_encodeFooters(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + + if(src->securityEnabled) { + // SecurityFooter + if(src->securityHeader.securityFooterEnabled) { + for(size_t i = 0; i < src->securityHeader.securityFooterSize; i++) { + UA_StatusCode rv = UA_Byte_encodeBinary(&(src->securityFooter.data[i]), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + } + } + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd, UA_Byte **dataToEncryptStart) { + + UA_StatusCode rv = UA_NetworkMessage_encodeHeaders(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + if(dataToEncryptStart) { + *dataToEncryptStart = *bufPos; + } + + rv = UA_NetworkMessage_encodePayload(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_NetworkMessage_encodeFooters(src, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_NetworkMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst) { + UA_Byte decoded = 0; + UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); + + dst->version = decoded & NM_VERSION_MASK; + + if((decoded & NM_PUBLISHER_ID_ENABLED_MASK) != 0) + dst->publisherIdEnabled = true; + + if((decoded & NM_GROUP_HEADER_ENABLED_MASK) != 0) + dst->groupHeaderEnabled = true; + + if((decoded & NM_PAYLOAD_HEADER_ENABLED_MASK) != 0) + dst->payloadHeaderEnabled = true; + + if((decoded & NM_EXTENDEDFLAGS1_ENABLED_MASK) != 0) { + decoded = 0; + rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); + + dst->publisherIdType = (UA_PublisherIdDatatype)(decoded & NM_PUBLISHER_ID_MASK); + if((decoded & NM_DATASET_CLASSID_ENABLED_MASK) != 0) + dst->dataSetClassIdEnabled = true; + + if((decoded & NM_SECURITY_ENABLED_MASK) != 0) + dst->securityEnabled = true; + + if((decoded & NM_TIMESTAMP_ENABLED_MASK) != 0) + dst->timestampEnabled = true; + + if((decoded & NM_PICOSECONDS_ENABLED_MASK) != 0) + dst->picosecondsEnabled = true; + + if((decoded & NM_EXTENDEDFLAGS2_ENABLED_MASK) != 0) { + decoded = 0; + rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); + + if((decoded & NM_CHUNK_MESSAGE_MASK) != 0) + dst->chunkMessage = true; + + if((decoded & NM_PROMOTEDFIELDS_ENABLED_MASK) != 0) + dst->promotedFieldsEnabled = true; + + decoded = decoded & NM_NETWORK_MSG_TYPE_MASK; + decoded = (UA_Byte) (decoded >> NM_SHIFT_LEN); + dst->networkMessageType = (UA_NetworkMessageType)decoded; + } + } + + if(dst->publisherIdEnabled) { + switch (dst->publisherIdType) { + case UA_PUBLISHERDATATYPE_BYTE: + rv = UA_Byte_decodeBinary(src, offset, &(dst->publisherId.publisherIdByte)); + break; + + case UA_PUBLISHERDATATYPE_UINT16: + rv = UA_UInt16_decodeBinary(src, offset, &(dst->publisherId.publisherIdUInt16)); + break; + + case UA_PUBLISHERDATATYPE_UINT32: + rv = UA_UInt32_decodeBinary(src, offset, &(dst->publisherId.publisherIdUInt32)); + break; + + case UA_PUBLISHERDATATYPE_UINT64: + rv = UA_UInt64_decodeBinary(src, offset, &(dst->publisherId.publisherIdUInt64)); + break; + + case UA_PUBLISHERDATATYPE_STRING: + rv = UA_String_decodeBinary(src, offset, &(dst->publisherId.publisherIdString)); + break; + + default: + rv = UA_STATUSCODE_BADINTERNALERROR; + break; + } + UA_CHECK_STATUS(rv, return rv); + } + + if(dst->dataSetClassIdEnabled) { + rv = UA_Guid_decodeBinary(src, offset, &(dst->dataSetClassId)); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_GroupHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { + UA_Byte decoded = 0; + UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); + + if((decoded & GROUP_HEADER_WRITER_GROUPID_ENABLED) != 0) + dst->groupHeader.writerGroupIdEnabled = true; + + if((decoded & GROUP_HEADER_GROUP_VERSION_ENABLED) != 0) + dst->groupHeader.groupVersionEnabled = true; + + if((decoded & GROUP_HEADER_NM_NUMBER_ENABLED) != 0) + dst->groupHeader.networkMessageNumberEnabled = true; + + if((decoded & GROUP_HEADER_SEQUENCE_NUMBER_ENABLED) != 0) + dst->groupHeader.sequenceNumberEnabled = true; + + if(dst->groupHeader.writerGroupIdEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.writerGroupId); + UA_CHECK_STATUS(rv, return rv); + } + if(dst->groupHeader.groupVersionEnabled) { + rv = UA_UInt32_decodeBinary(src, offset, &dst->groupHeader.groupVersion); + UA_CHECK_STATUS(rv, return rv); + } + if(dst->groupHeader.networkMessageNumberEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.networkMessageNumber); + UA_CHECK_STATUS(rv, return rv); + } + if(dst->groupHeader.sequenceNumberEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.sequenceNumber); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_PayloadHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { + + if(dst->networkMessageType != UA_NETWORKMESSAGE_DATASET) + return UA_STATUSCODE_BADNOTIMPLEMENTED; + + UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &dst->payloadHeader.dataSetPayloadHeader.count); + UA_CHECK_STATUS(rv, return rv); + + dst->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = + (UA_UInt16 *)UA_Array_new(dst->payloadHeader.dataSetPayloadHeader.count, + &UA_TYPES[UA_TYPES_UINT16]); + for (UA_Byte i = 0; i < dst->payloadHeader.dataSetPayloadHeader.count; i++) { + rv = UA_UInt16_decodeBinary(src, offset, + &dst->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[i]); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + +static UA_StatusCode +UA_ExtendedNetworkMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { + UA_StatusCode rv; + + // Timestamp + if(dst->timestampEnabled) { + rv = UA_DateTime_decodeBinary(src, offset, &(dst->timestamp)); + UA_CHECK_STATUS(rv, goto error); + } + + // Picoseconds + if(dst->picosecondsEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &(dst->picoseconds)); + UA_CHECK_STATUS(rv, goto error); + } + + // PromotedFields + if(dst->promotedFieldsEnabled) { + // Size + UA_UInt16 promotedFieldsSize = 0; + rv = UA_UInt16_decodeBinary(src, offset, &promotedFieldsSize); + UA_CHECK_STATUS(rv, goto error); + + // promotedFieldsSize: here size in Byte, not the number of objects! + if(promotedFieldsSize > 0) { + // store offset, later compared with promotedFieldsSize + size_t offsetEnd = (*offset) + promotedFieldsSize; + + unsigned int counter = 0; + do { + if(counter == 0) { + dst->promotedFields = (UA_Variant*)UA_malloc(UA_TYPES[UA_TYPES_VARIANT].memSize); + UA_CHECK_MEM(dst->promotedFields, + return UA_STATUSCODE_BADOUTOFMEMORY); + // set promotedFieldsSize to the number of objects + dst->promotedFieldsSize = (UA_UInt16) (counter + 1); + } else { + dst->promotedFields = (UA_Variant*) + UA_realloc(dst->promotedFields, + (size_t) UA_TYPES[UA_TYPES_VARIANT].memSize * (counter + 1)); + UA_CHECK_MEM(dst->promotedFields, + return UA_STATUSCODE_BADOUTOFMEMORY); + // set promotedFieldsSize to the number of objects + dst->promotedFieldsSize = (UA_UInt16) (counter + 1); + } + + UA_Variant_init(&dst->promotedFields[counter]); + rv = UA_Variant_decodeBinary(src, offset, &dst->promotedFields[counter]); + UA_CHECK_STATUS(rv, goto error); + + counter++; + } while ((*offset) < offsetEnd); + } + } + return UA_STATUSCODE_GOOD; + +error: + if (dst->promotedFields) { + UA_free(dst->promotedFields); + } + return rv; +} + +static UA_StatusCode +UA_SecurityHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { + UA_Byte decoded = 0; + // SecurityFlags + decoded = 0; + UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &decoded); + UA_CHECK_STATUS(rv, return rv); + + if((decoded & SECURITY_HEADER_NM_SIGNED) != 0) + dst->securityHeader.networkMessageSigned = true; + + if((decoded & SECURITY_HEADER_NM_ENCRYPTED) != 0) + dst->securityHeader.networkMessageEncrypted = true; + + if((decoded & SECURITY_HEADER_SEC_FOOTER_ENABLED) != 0) + dst->securityHeader.securityFooterEnabled = true; + + if((decoded & SECURITY_HEADER_FORCE_KEY_RESET) != 0) + dst->securityHeader.forceKeyReset = true; + + // SecurityTokenId + rv = UA_UInt32_decodeBinary(src, offset, &dst->securityHeader.securityTokenId); + UA_CHECK_STATUS(rv, return rv); + + // NonceLength + UA_Byte nonceLength; + rv = UA_Byte_decodeBinary(src, offset, &nonceLength); + UA_CHECK_STATUS(rv, return rv); + + // MessageNonce + if(nonceLength > 0) { + //TODO: check for memory leaks + rv = UA_ByteString_allocBuffer(&dst->securityHeader.messageNonce, nonceLength); + UA_CHECK_STATUS(rv, return rv); + for (UA_Byte i = 0; i < nonceLength; i++) { + rv = UA_Byte_decodeBinary(src, offset, + &dst->securityHeader.messageNonce.data[i]); + UA_CHECK_STATUS(rv, return rv); + } + } + // SecurityFooterSize + if(dst->securityHeader.securityFooterEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->securityHeader.securityFooterSize); + UA_CHECK_STATUS(rv, return rv); + } + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_NetworkMessage_decodeHeaders(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst) { + + UA_StatusCode rv = UA_NetworkMessageHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + if (dst->groupHeaderEnabled) { + rv = UA_GroupHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + } + + if (dst->payloadHeaderEnabled) { + rv = UA_PayloadHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + } + + if (dst->securityEnabled) { + rv = UA_SecurityHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + } + + rv = UA_ExtendedNetworkMessageHeader_decodeBinary(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_NetworkMessage_decodePayload(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst) { + + // Payload + if(dst->networkMessageType != UA_NETWORKMESSAGE_DATASET) + return UA_STATUSCODE_BADNOTIMPLEMENTED; + + UA_StatusCode rv; + + UA_Byte count = 1; + if(dst->payloadHeaderEnabled) { + count = dst->payloadHeader.dataSetPayloadHeader.count; + if(count > 1) { + dst->payload.dataSetPayload.sizes = (UA_UInt16 *)UA_Array_new(count, &UA_TYPES[UA_TYPES_UINT16]); + for (UA_Byte i = 0; i < count; i++) { + rv = UA_UInt16_decodeBinary(src, offset, &(dst->payload.dataSetPayload.sizes[i])); + UA_CHECK_STATUS(rv, return rv); + } + } + } + + dst->payload.dataSetPayload.dataSetMessages = (UA_DataSetMessage*) + UA_calloc(count, sizeof(UA_DataSetMessage)); + UA_CHECK_MEM(dst->payload.dataSetPayload.dataSetMessages, + return UA_STATUSCODE_BADOUTOFMEMORY); + + for(UA_Byte i = 0; i < count; i++) { + if(&dst->payload.dataSetPayload.sizes[i] == NULL){ + rv = UA_DataSetMessage_decodeBinary(src, offset, + &(dst->payload.dataSetPayload.dataSetMessages[i]), + 0); + } else { + rv = UA_DataSetMessage_decodeBinary(src, offset, + &(dst->payload.dataSetPayload.dataSetMessages[i]), + dst->payload.dataSetPayload.sizes[i]); + } + UA_CHECK_STATUS(rv, return rv); + } + + return UA_STATUSCODE_GOOD; + + /** + * TODO: check if making the cleanup to free its own allocated memory is better, + * currently the free happens in a parent context + */ + // error: + // if (dst->payload.dataSetPayload.dataSetMessages) { + // UA_free(dst->payload.dataSetPayload.dataSetMessages); + // } + // return rv; +} + +UA_StatusCode +UA_NetworkMessage_decodeFooters(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst) { + + if (dst->securityEnabled) { + // SecurityFooter + if(dst->securityHeader.securityFooterEnabled && + (dst->securityHeader.securityFooterSize > 0)) { + UA_StatusCode rv = UA_ByteString_allocBuffer(&dst->securityFooter, + dst->securityHeader.securityFooterSize); + UA_CHECK_STATUS(rv, return rv); + + for(UA_UInt16 i = 0; i < dst->securityHeader.securityFooterSize; i++) { + rv = UA_Byte_decodeBinary(src, offset, &(dst->securityFooter.data[i])); + UA_CHECK_STATUS(rv, return rv); + } + } + } + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_NetworkMessage_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_NetworkMessage* dst) { + + UA_StatusCode rv = UA_STATUSCODE_GOOD; + + /* headers only need to be decoded when not in encryption mode + * because headers are already decoded when encryption mode is enabled + * to check for security parameters and decrypt/verify + * + * TODO: check if there is a workaround to use this function + * also when encryption is enabled + */ + // #ifndef UA_ENABLE_PUBSUB_ENCRYPTION + // if (*offset == 0) { + // rv = UA_NetworkMessage_decodeHeaders(src, offset, dst); + // UA_CHECK_STATUS(rv, return rv); + // } + // #endif + + rv = UA_NetworkMessage_decodeHeaders(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_NetworkMessage_decodePayload(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_NetworkMessage_decodeFooters(src, offset, dst); + UA_CHECK_STATUS(rv, return rv); + + return UA_STATUSCODE_GOOD; +} + +static UA_Boolean +increaseOffsetArray(UA_NetworkMessageOffsetBuffer *offsetBuffer) { + UA_NetworkMessageOffset *tmpOffsets = (UA_NetworkMessageOffset *) + UA_realloc(offsetBuffer->offsets, sizeof(UA_NetworkMessageOffset) * (offsetBuffer->offsetsSize + (size_t)1)); + UA_CHECK_MEM(tmpOffsets, return false); + + offsetBuffer->offsets = tmpOffsets; + offsetBuffer->offsetsSize++; + return true; +} + +size_t +UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p, UA_NetworkMessageOffsetBuffer *offsetBuffer) { + size_t retval = 0; + UA_Byte byte = 0; + size_t size = UA_Byte_calcSizeBinary(&byte); // UADPVersion + UADPFlags + if(UA_NetworkMessage_ExtendedFlags1Enabled(p)) { + size += UA_Byte_calcSizeBinary(&byte); + if(UA_NetworkMessage_ExtendedFlags2Enabled(p)) + size += UA_Byte_calcSizeBinary(&byte); + } + + if(p->publisherIdEnabled) { + if(offsetBuffer && offsetBuffer->RTsubscriberEnabled){ + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_PUBLISHERID; + } + switch (p->publisherIdType) { + case UA_PUBLISHERDATATYPE_BYTE: + size += UA_Byte_calcSizeBinary(&p->publisherId.publisherIdByte); + break; + + case UA_PUBLISHERDATATYPE_UINT16: + size += UA_UInt16_calcSizeBinary(&p->publisherId.publisherIdUInt16); + break; + + case UA_PUBLISHERDATATYPE_UINT32: + size += UA_UInt32_calcSizeBinary(&p->publisherId.publisherIdUInt32); + break; + + case UA_PUBLISHERDATATYPE_UINT64: + size += UA_UInt64_calcSizeBinary(&p->publisherId.publisherIdUInt64); + break; + + case UA_PUBLISHERDATATYPE_STRING: + size += UA_String_calcSizeBinary(&p->publisherId.publisherIdString); + break; + } + } + + if(p->dataSetClassIdEnabled) + size += UA_Guid_calcSizeBinary(&p->dataSetClassId); + + // Group Header + if(p->groupHeaderEnabled) { + size += UA_Byte_calcSizeBinary(&byte); + + if(p->groupHeader.writerGroupIdEnabled) { + if(offsetBuffer && offsetBuffer->RTsubscriberEnabled){ + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_WRITERGROUPID; + } + size += UA_UInt16_calcSizeBinary(&p->groupHeader.writerGroupId); + } + + if(p->groupHeader.groupVersionEnabled) + size += UA_UInt32_calcSizeBinary(&p->groupHeader.groupVersion); + + if(p->groupHeader.networkMessageNumberEnabled) { + size += UA_UInt16_calcSizeBinary(&p->groupHeader.networkMessageNumber); + } + + if(p->groupHeader.sequenceNumberEnabled){ + if(offsetBuffer){ + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); + UA_DataValue_init(offsetBuffer->offsets[pos].offsetData.value.value); + UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, + &p->groupHeader.sequenceNumber, &UA_TYPES[UA_TYPES_UINT16]); + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER; + } + size += UA_UInt16_calcSizeBinary(&p->groupHeader.sequenceNumber); + } + } + + // Payload Header + if(p->payloadHeaderEnabled) { + if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) { + size += UA_Byte_calcSizeBinary(&p->payloadHeader.dataSetPayloadHeader.count); + if(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds != NULL) { + if(offsetBuffer && offsetBuffer->RTsubscriberEnabled){ + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_DATASETWRITERID; + } + size += UA_UInt16_calcSizeBinary(&p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0]) * + p->payloadHeader.dataSetPayloadHeader.count; + } else { + return 0; /* no dataSetWriterIds given! */ + } + } else { + // not implemented + } + } + + if(p->timestampEnabled) { + if(offsetBuffer){ + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_TIMESTAMP; + } + size += UA_DateTime_calcSizeBinary(&p->timestamp); + } + + if(p->picosecondsEnabled){ + if (offsetBuffer) { + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_TIMESTAMP_PICOSECONDS; + } + size += UA_UInt16_calcSizeBinary(&p->picoseconds); + } + + if(p->promotedFieldsEnabled) { + size += UA_UInt16_calcSizeBinary(&p->promotedFieldsSize); + for (UA_UInt16 i = 0; i < p->promotedFieldsSize; i++) + size += UA_Variant_calcSizeBinary(&p->promotedFields[i]); + } + + if(p->securityEnabled) { + size += UA_Byte_calcSizeBinary(&byte); + size += UA_UInt32_calcSizeBinary(&p->securityHeader.securityTokenId); + size += 1; /* UA_Byte_calcSizeBinary(&p->securityHeader.nonceLength); */ + size += p->securityHeader.messageNonce.length; + if(p->securityHeader.securityFooterEnabled) + size += UA_UInt16_calcSizeBinary(&p->securityHeader.securityFooterSize); + } + + if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) { + UA_Byte count = 1; + if(p->payloadHeaderEnabled) { + count = p->payloadHeader.dataSetPayloadHeader.count; + if(count > 1) + size += UA_UInt16_calcSizeBinary(&(p->payload.dataSetPayload.sizes[0])) * count; + } + + for (size_t i = 0; i < count; i++) { + if (offsetBuffer) + UA_DataSetMessage_calcSizeBinary(&(p->payload.dataSetPayload.dataSetMessages[i]), offsetBuffer, + size); + size += UA_DataSetMessage_calcSizeBinary(&(p->payload.dataSetPayload.dataSetMessages[i]), NULL, 0); + } + } + + if(p->securityEnabled) { + if(p->securityHeader.securityFooterEnabled) + size += p->securityHeader.securityFooterSize; + } + + retval = size; + return retval; +} + +void +UA_NetworkMessage_clear(UA_NetworkMessage* p) { + if(p->promotedFieldsEnabled) + UA_Array_delete(p->promotedFields, p->promotedFieldsSize, &UA_TYPES[UA_TYPES_VARIANT]); + + UA_ByteString_clear(&p->securityHeader.messageNonce); + + if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) { + if(p->payloadHeaderEnabled) { + if(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds != NULL) { + UA_Array_delete(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds, + p->payloadHeader.dataSetPayloadHeader.count, &UA_TYPES[UA_TYPES_UINT16]); + } + if(p->payload.dataSetPayload.sizes != NULL) { + UA_Array_delete(p->payload.dataSetPayload.sizes, + p->payloadHeader.dataSetPayloadHeader.count, &UA_TYPES[UA_TYPES_UINT16]); + } + } + + if(p->payload.dataSetPayload.dataSetMessages) { + UA_Byte count = 1; + if(p->payloadHeaderEnabled) + count = p->payloadHeader.dataSetPayloadHeader.count; + + for(size_t i = 0; i < count; i++) + UA_DataSetMessage_clear(&(p->payload.dataSetPayload.dataSetMessages[i])); + + UA_free(p->payload.dataSetPayload.dataSetMessages); + } + } + + if(p->securityHeader.securityFooterEnabled && (p->securityHeader.securityFooterSize > 0)) + UA_ByteString_clear(&p->securityFooter); + + if(p->messageIdEnabled){ + UA_String_clear(&p->messageId); + } + + if(p->publisherIdEnabled && p->publisherIdType == UA_PUBLISHERDATATYPE_STRING){ + UA_String_clear(&p->publisherId.publisherIdString); + } + + memset(p, 0, sizeof(UA_NetworkMessage)); +} + +void UA_NetworkMessage_delete(UA_NetworkMessage* p) { + UA_NetworkMessage_clear(p); +} + +UA_Boolean +UA_NetworkMessage_ExtendedFlags1Enabled(const UA_NetworkMessage* src) { + UA_Boolean retval = false; + + if((src->publisherIdType != UA_PUBLISHERDATATYPE_BYTE) + || src->dataSetClassIdEnabled + || src->securityEnabled + || src->timestampEnabled + || src->picosecondsEnabled + || UA_NetworkMessage_ExtendedFlags2Enabled(src)) + { + retval = true; + } + + return retval; +} + +UA_Boolean +UA_NetworkMessage_ExtendedFlags2Enabled(const UA_NetworkMessage* src) { + if(src->chunkMessage || src->promotedFieldsEnabled || + src->networkMessageType != UA_NETWORKMESSAGE_DATASET) + return true; + return false; +} + +UA_Boolean +UA_DataSetMessageHeader_DataSetFlags2Enabled(const UA_DataSetMessageHeader* src) { + if(src->dataSetMessageType != UA_DATASETMESSAGE_DATAKEYFRAME || + src->timestampEnabled || src->picoSecondsIncluded) + return true; + return false; +} + +UA_StatusCode +UA_DataSetMessageHeader_encodeBinary(const UA_DataSetMessageHeader* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + UA_Byte v; + // DataSetFlags1 + v = (UA_Byte)src->fieldEncoding; + // shift left 1 bit + v = (UA_Byte)(v << DS_MH_SHIFT_LEN); + + if(src->dataSetMessageValid) + v |= DS_MESSAGEHEADER_DS_MSG_VALID; + + if(src->dataSetMessageSequenceNrEnabled) + v |= DS_MESSAGEHEADER_SEQ_NR_ENABLED_MASK; + + if(src->statusEnabled) + v |= DS_MESSAGEHEADER_STATUS_ENABLED_MASK; + + if(src->configVersionMajorVersionEnabled) + v |= DS_MESSAGEHEADER_CONFIGMAJORVERSION_ENABLED_MASK; + + if(src->configVersionMinorVersionEnabled) + v |= DS_MESSAGEHEADER_CONFIGMINORVERSION_ENABLED_MASK; + + if(UA_DataSetMessageHeader_DataSetFlags2Enabled(src)) + v |= DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK; + + UA_StatusCode rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + // DataSetFlags2 + if(UA_DataSetMessageHeader_DataSetFlags2Enabled(src)) { + v = (UA_Byte)src->dataSetMessageType; + + if(src->timestampEnabled) + v |= DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK; + + if(src->picoSecondsIncluded) + v |= DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK; + + rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + // DataSetMessageSequenceNr + if(src->dataSetMessageSequenceNrEnabled) { + rv = UA_UInt16_encodeBinary(&src->dataSetMessageSequenceNr, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + // Timestamp + if(src->timestampEnabled) { + rv = UA_DateTime_encodeBinary(&(src->timestamp), bufPos, bufEnd); /* UtcTime */ + UA_CHECK_STATUS(rv, return rv); + } + + // PicoSeconds + if(src->picoSecondsIncluded) { + rv = UA_UInt16_encodeBinary(&(src->picoSeconds), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + // Status + if(src->statusEnabled) { + rv = UA_UInt16_encodeBinary(&(src->status), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + // ConfigVersionMajorVersion + if(src->configVersionMajorVersionEnabled) { + rv = UA_UInt32_encodeBinary(&(src->configVersionMajorVersion), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + // ConfigVersionMinorVersion + if(src->configVersionMinorVersionEnabled) { + rv = UA_UInt32_encodeBinary(&(src->configVersionMinorVersion), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + + return UA_STATUSCODE_GOOD; +} + +#ifdef UA_ENABLE_PUBSUB_ENCRYPTION + +UA_StatusCode +UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm, UA_MessageSecurityMode securityMode, + UA_PubSubSecurityPolicy *policy, void *policyContext, + UA_Byte *messageStart, UA_Byte *encryptStart, + UA_Byte *sigStart) { + UA_StatusCode res = UA_STATUSCODE_GOOD; + + /* Encrypt the payload */ + if(securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + /* Set the temporary MessageNonce in the SecurityPolicy */ + res = policy->setMessageNonce(policyContext, &nm->securityHeader.messageNonce); + UA_CHECK_STATUS(res, return res); + + /* The encryption is done in-place, no need to encode again */ + UA_ByteString encryptBuf; + encryptBuf.data = encryptStart; + encryptBuf.length = (uintptr_t)sigStart - (uintptr_t)encryptStart; + res = policy->symmetricModule.cryptoModule.encryptionAlgorithm. + encrypt(policyContext, &encryptBuf); + UA_CHECK_STATUS(res, return res); + } + + /* Sign the entire message */ + if(securityMode == UA_MESSAGESECURITYMODE_SIGN || + securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { + UA_ByteString sigBuf; + sigBuf.length = (uintptr_t)sigStart - (uintptr_t)messageStart; + sigBuf.data = messageStart; + size_t sigSize = policy->symmetricModule.cryptoModule. + signatureAlgorithm.getLocalSignatureSize(policyContext); + UA_ByteString sig = {sigSize, sigStart}; + res = policy->symmetricModule.cryptoModule. + signatureAlgorithm.sign(policyContext, &sigBuf, &sig); + } + + return res; +} +#endif + +UA_StatusCode +UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset, + UA_DataSetMessageHeader* dst) { + memset(dst, 0, sizeof(UA_DataSetMessageHeader)); + UA_Byte v = 0; + UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &v); + UA_CHECK_STATUS(rv, return rv); + + UA_Byte v2 = v & DS_MESSAGEHEADER_FIELD_ENCODING_MASK; + v2 = (UA_Byte)(v2 >> DS_MH_SHIFT_LEN); + dst->fieldEncoding = (UA_FieldEncoding)v2; + + if((v & DS_MESSAGEHEADER_DS_MSG_VALID) != 0) + dst->dataSetMessageValid = true; + + if((v & DS_MESSAGEHEADER_SEQ_NR_ENABLED_MASK) != 0) + dst->dataSetMessageSequenceNrEnabled = true; + + if((v & DS_MESSAGEHEADER_STATUS_ENABLED_MASK) != 0) + dst->statusEnabled = true; + + if((v & DS_MESSAGEHEADER_CONFIGMAJORVERSION_ENABLED_MASK) != 0) + dst->configVersionMajorVersionEnabled = true; + + if((v & DS_MESSAGEHEADER_CONFIGMINORVERSION_ENABLED_MASK) != 0) + dst->configVersionMinorVersionEnabled = true; + + if((v & DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK) != 0) { + v = 0; + rv = UA_Byte_decodeBinary(src, offset, &v); + UA_CHECK_STATUS(rv, return rv); + + dst->dataSetMessageType = (UA_DataSetMessageType)(v & DS_MESSAGEHEADER_DS_MESSAGE_TYPE_MASK); + + if((v & DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK) != 0) + dst->timestampEnabled = true; + + if((v & DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK) != 0) + dst->picoSecondsIncluded = true; + } else { + dst->dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME; + dst->picoSecondsIncluded = false; + } + + if(dst->dataSetMessageSequenceNrEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->dataSetMessageSequenceNr); + UA_CHECK_STATUS(rv, return rv); + } else { + dst->dataSetMessageSequenceNr = 0; + } + + if(dst->timestampEnabled) { + rv = UA_DateTime_decodeBinary(src, offset, &dst->timestamp); /* UtcTime */ + UA_CHECK_STATUS(rv, return rv); + } else { + dst->timestamp = 0; + } + + if(dst->picoSecondsIncluded) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->picoSeconds); + UA_CHECK_STATUS(rv, return rv); + } else { + dst->picoSeconds = 0; + } + + if(dst->statusEnabled) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->status); + UA_CHECK_STATUS(rv, return rv); + } else { + dst->status = 0; + } + + if(dst->configVersionMajorVersionEnabled) { + rv = UA_UInt32_decodeBinary(src, offset, &dst->configVersionMajorVersion); + UA_CHECK_STATUS(rv, return rv); + } else { + dst->configVersionMajorVersion = 0; + } + + if(dst->configVersionMinorVersionEnabled) { + rv = UA_UInt32_decodeBinary(src, offset, &dst->configVersionMinorVersion); + UA_CHECK_STATUS(rv, return rv); + } else { + dst->configVersionMinorVersion = 0; + } + + return UA_STATUSCODE_GOOD; +} + +size_t +UA_DataSetMessageHeader_calcSizeBinary(const UA_DataSetMessageHeader* p) { + UA_Byte byte = 0; + size_t size = UA_Byte_calcSizeBinary(&byte); // DataSetMessage Type + Flags + if(UA_DataSetMessageHeader_DataSetFlags2Enabled(p)) + size += UA_Byte_calcSizeBinary(&byte); + + if(p->dataSetMessageSequenceNrEnabled) + size += UA_UInt16_calcSizeBinary(&p->dataSetMessageSequenceNr); + + if(p->timestampEnabled) + size += UA_DateTime_calcSizeBinary(&p->timestamp); /* UtcTime */ + + if(p->picoSecondsIncluded) + size += UA_UInt16_calcSizeBinary(&p->picoSeconds); + + if(p->statusEnabled) + size += UA_UInt16_calcSizeBinary(&p->status); + + if(p->configVersionMajorVersionEnabled) + size += UA_UInt32_calcSizeBinary(&p->configVersionMajorVersion); + + if(p->configVersionMinorVersionEnabled) + size += UA_UInt32_calcSizeBinary(&p->configVersionMinorVersion); + + return size; +} + +UA_StatusCode +UA_DataSetMessage_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos, + const UA_Byte *bufEnd) { + UA_StatusCode rv = UA_DataSetMessageHeader_encodeBinary(&src->header, bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) { + if(src->header.fieldEncoding != UA_FIELDENCODING_RAWDATA) { + rv = UA_UInt16_encodeBinary(&(src->data.keyFrameData.fieldCount), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { + for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) { + rv = UA_Variant_encodeBinary(&(src->data.keyFrameData.dataSetFields[i].value), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + } else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { + for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) { + rv = UA_encodeBinaryInternal(src->data.keyFrameData.dataSetFields[i].value.data, + src->data.keyFrameData.dataSetFields[i].value.type, + bufPos, &bufEnd, NULL, NULL); + UA_CHECK_STATUS(rv, return rv); + } + } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { + for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) { + rv = UA_DataValue_encodeBinary(&(src->data.keyFrameData.dataSetFields[i]), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + } + } else if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) { + // Encode Delta Frame + // Here the FieldCount is always present + rv = UA_UInt16_encodeBinary(&(src->data.keyFrameData.fieldCount), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { + for (UA_UInt16 i = 0; i < src->data.deltaFrameData.fieldCount; i++) { + rv = UA_UInt16_encodeBinary(&(src->data.deltaFrameData.deltaFrameFields[i].fieldIndex), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_Variant_encodeBinary(&(src->data.deltaFrameData.deltaFrameFields[i].fieldValue.value), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + } else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { + for (UA_UInt16 i = 0; i < src->data.deltaFrameData.fieldCount; i++) { + rv = UA_UInt16_encodeBinary(&(src->data.deltaFrameData.deltaFrameFields[i].fieldIndex), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_DataValue_encodeBinary(&(src->data.deltaFrameData.deltaFrameFields[i].fieldValue), bufPos, bufEnd); + UA_CHECK_STATUS(rv, return rv); + } + } + } else if(src->header.dataSetMessageType != UA_DATASETMESSAGE_KEEPALIVE) { + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } + + /* Keep-Alive Message contains no Payload Data */ + return UA_STATUSCODE_GOOD; +} + +UA_StatusCode +UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset, UA_DataSetMessage* dst, UA_UInt16 dsmSize) { + size_t initialOffset = *offset; + memset(dst, 0, sizeof(UA_DataSetMessage)); + UA_StatusCode rv = UA_DataSetMessageHeader_decodeBinary(src, offset, &dst->header); + UA_CHECK_STATUS(rv, return rv); + + if(dst->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) { + switch(dst->header.fieldEncoding) { + case UA_FIELDENCODING_VARIANT: + { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.keyFrameData.fieldCount); + UA_CHECK_STATUS(rv, return rv); + dst->data.keyFrameData.dataSetFields = + (UA_DataValue *)UA_Array_new(dst->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]); + for (UA_UInt16 i = 0; i < dst->data.keyFrameData.fieldCount; i++) { + UA_DataValue_init(&dst->data.keyFrameData.dataSetFields[i]); + rv = UA_Variant_decodeBinary(src, offset, &dst->data.keyFrameData.dataSetFields[i].value); + UA_CHECK_STATUS(rv, return rv); + + dst->data.keyFrameData.dataSetFields[i].hasValue = true; + } + break; + } + case UA_FIELDENCODING_DATAVALUE: + { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.keyFrameData.fieldCount); + UA_CHECK_STATUS(rv, return rv); + dst->data.keyFrameData.dataSetFields = + (UA_DataValue *)UA_Array_new(dst->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]); + for (UA_UInt16 i = 0; i < dst->data.keyFrameData.fieldCount; i++) { + rv = UA_DataValue_decodeBinary(src, offset, &(dst->data.keyFrameData.dataSetFields[i])); + UA_CHECK_STATUS(rv, return rv); + } + break; + } + case UA_FIELDENCODING_RAWDATA: + { + dst->data.keyFrameData.rawFields.data = &src->data[*offset]; + dst->data.keyFrameData.rawFields.length = dsmSize; + if(dsmSize == 0){ + //TODO calculate the length of the DSM-Payload for a single DSM + //Problem: Size is not set and MetaData information are needed. + //Increase offset to avoid endless chunk loop. Needs to be fixed when + //pubsub security footer and signatur is enabled. + *offset += 1500; + } else { + *offset += (dsmSize - (*offset - initialOffset)); + } + break; + } + default: + return UA_STATUSCODE_BADINTERNALERROR; + } + } else if(dst->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) { + switch(dst->header.fieldEncoding) { + case UA_FIELDENCODING_VARIANT: { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.deltaFrameData.fieldCount); + UA_CHECK_STATUS(rv, return rv); + size_t memsize = sizeof(UA_DataSetMessage_DeltaFrameField) * dst->data.deltaFrameData.fieldCount; + dst->data.deltaFrameData.deltaFrameFields = (UA_DataSetMessage_DeltaFrameField*)UA_malloc(memsize); + for (UA_UInt16 i = 0; i < dst->data.deltaFrameData.fieldCount; i++) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.deltaFrameData.deltaFrameFields[i].fieldIndex); + UA_CHECK_STATUS(rv, return rv); + + UA_DataValue_init(&dst->data.deltaFrameData.deltaFrameFields[i].fieldValue); + rv = UA_Variant_decodeBinary(src, offset, &dst->data.deltaFrameData.deltaFrameFields[i].fieldValue.value); + UA_CHECK_STATUS(rv, return rv); + + dst->data.deltaFrameData.deltaFrameFields[i].fieldValue.hasValue = true; + } + break; + } + case UA_FIELDENCODING_DATAVALUE: { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.deltaFrameData.fieldCount); + UA_CHECK_STATUS(rv, return rv); + size_t memsize = sizeof(UA_DataSetMessage_DeltaFrameField) * dst->data.deltaFrameData.fieldCount; + dst->data.deltaFrameData.deltaFrameFields = (UA_DataSetMessage_DeltaFrameField*)UA_malloc(memsize); + for (UA_UInt16 i = 0; i < dst->data.deltaFrameData.fieldCount; i++) { + rv = UA_UInt16_decodeBinary(src, offset, &dst->data.deltaFrameData.deltaFrameFields[i].fieldIndex); + UA_CHECK_STATUS(rv, return rv); + + rv = UA_DataValue_decodeBinary(src, offset, &(dst->data.deltaFrameData.deltaFrameFields[i].fieldValue)); + UA_CHECK_STATUS(rv, return rv); + } + break; + } + case UA_FIELDENCODING_RAWDATA: { + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } + default: + return UA_STATUSCODE_BADINTERNALERROR; + } + } else if(dst->header.dataSetMessageType != UA_DATASETMESSAGE_KEEPALIVE) { + return UA_STATUSCODE_BADNOTIMPLEMENTED; + } + + /* Keep-Alive Message contains no Payload Data */ + return UA_STATUSCODE_GOOD; +} + +size_t +UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage* p, UA_NetworkMessageOffsetBuffer *offsetBuffer, size_t currentOffset) { + size_t size = currentOffset; + if (offsetBuffer) { + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); + UA_DataValue_init(offsetBuffer->offsets[pos].offsetData.value.value); + UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, + &p->header.fieldEncoding, &UA_TYPES[UA_TYPES_UINT32]); + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING; + } + UA_Byte byte = 0; + size += UA_Byte_calcSizeBinary(&byte); // DataSetMessage Type + Flags + if(UA_DataSetMessageHeader_DataSetFlags2Enabled(&p->header)) + size += UA_Byte_calcSizeBinary(&byte); + + if(p->header.dataSetMessageSequenceNrEnabled) { + if (offsetBuffer) { + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); + UA_DataValue_init(offsetBuffer->offsets[pos].offsetData.value.value); + UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, + &p->header.dataSetMessageSequenceNr, &UA_TYPES[UA_TYPES_UINT16]); + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER; + } + size += UA_UInt16_calcSizeBinary(&p->header.dataSetMessageSequenceNr); + } + + if(p->header.timestampEnabled) + size += UA_DateTime_calcSizeBinary(&p->header.timestamp); /* UtcTime */ + + if(p->header.picoSecondsIncluded) + size += UA_UInt16_calcSizeBinary(&p->header.picoSeconds); + + if(p->header.statusEnabled) + size += UA_UInt16_calcSizeBinary(&p->header.status); + + if(p->header.configVersionMajorVersionEnabled) + size += UA_UInt32_calcSizeBinary(&p->header.configVersionMajorVersion); + + if(p->header.configVersionMinorVersionEnabled) + size += UA_UInt32_calcSizeBinary(&p->header.configVersionMinorVersion); + + if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) { + if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA){ + size += UA_calcSizeBinary(&p->data.keyFrameData.fieldCount, &UA_TYPES[UA_TYPES_UINT16]); + } + if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { + for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++){ + if (offsetBuffer) { + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT; + //TODO check value source and alloc! + //offsetBuffer->offsets[pos].offsetData.value.value = p->data.keyFrameData.dataSetFields; + offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); + UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, + p->data.keyFrameData.dataSetFields[i].value.data, + p->data.keyFrameData.dataSetFields[i].value.type); + offsetBuffer->offsets[pos].offsetData.value.value->value.storageType = UA_VARIANT_DATA_NODELETE; + } + size += UA_calcSizeBinary(&p->data.keyFrameData.dataSetFields[i].value, &UA_TYPES[UA_TYPES_VARIANT]); + } + } else if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { + for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++){ + if (offsetBuffer) { + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW; + offsetBuffer->offsets[pos].offsetData.value.value = UA_DataValue_new(); + //init offset buffer with the latest value + UA_Variant_setScalar(&offsetBuffer->offsets[pos].offsetData.value.value->value, + p->data.keyFrameData.dataSetFields[i].value.data, + p->data.keyFrameData.dataSetFields[i].value.type); + offsetBuffer->offsets[pos].offsetData.value.value->value.storageType = UA_VARIANT_DATA_NODELETE; + //count the memory size of the specific field + offsetBuffer->rawMessageLength += p->data.keyFrameData.dataSetFields[i].value.type->memSize; + } + size += UA_calcSizeBinary(p->data.keyFrameData.dataSetFields[i].value.data, + p->data.keyFrameData.dataSetFields[i].value.type); + } + } else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { + for (UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++) { + if (offsetBuffer) { + size_t pos = offsetBuffer->offsetsSize; + if(!increaseOffsetArray(offsetBuffer)) + return 0; + offsetBuffer->offsets[pos].offset = size; + offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE; + //TODO check value source, change implementation to 'variant' + offsetBuffer->offsets[pos].offsetData.value.value = p->data.keyFrameData.dataSetFields; + } + size += UA_calcSizeBinary(&p->data.keyFrameData.dataSetFields[i], &UA_TYPES[UA_TYPES_DATAVALUE]); + } + } + } else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) { + //TODO clarify how to handle DATADELTAFRAME messages with RT + if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA) + size += UA_calcSizeBinary(&p->data.deltaFrameData.fieldCount, &UA_TYPES[UA_TYPES_UINT16]); + + if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { + for (UA_UInt16 i = 0; i < p->data.deltaFrameData.fieldCount; i++) { + size += UA_calcSizeBinary(&p->data.deltaFrameData.deltaFrameFields[i].fieldIndex, &UA_TYPES[UA_TYPES_UINT16]); + size += UA_calcSizeBinary(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue.value, &UA_TYPES[UA_TYPES_VARIANT]); + } + } else if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) { + // not implemented + } else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { + for (UA_UInt16 i = 0; i < p->data.deltaFrameData.fieldCount; i++) { + size += UA_calcSizeBinary(&p->data.deltaFrameData.deltaFrameFields[i].fieldIndex, &UA_TYPES[UA_TYPES_UINT16]); + size += UA_calcSizeBinary(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue, &UA_TYPES[UA_TYPES_DATAVALUE]); + } + } + } + /* KeepAlive-Message contains no Payload Data */ + return size; +} + +void +UA_DataSetMessage_clear(const UA_DataSetMessage* p) { + if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) { + if(p->data.keyFrameData.dataSetFields != NULL) { + UA_Array_delete(p->data.keyFrameData.dataSetFields, + p->data.keyFrameData.fieldCount, + &UA_TYPES[UA_TYPES_DATAVALUE]); + } + + /* Json keys */ + if(p->data.keyFrameData.fieldNames != NULL){ + UA_Array_delete(p->data.keyFrameData.fieldNames, + p->data.keyFrameData.fieldCount, + &UA_TYPES[UA_TYPES_STRING]); + } + } else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) { + if(p->data.deltaFrameData.deltaFrameFields != NULL) { + for(UA_UInt16 i = 0; i < p->data.deltaFrameData.fieldCount; i++) { + if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) { + UA_DataValue_clear(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue); + } else if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) { + UA_Variant_clear(&p->data.deltaFrameData.deltaFrameFields[i].fieldValue.value); + } + } + UA_free(p->data.deltaFrameData.deltaFrameFields); + } + } +} +#endif /* UA_ENABLE_PUBSUB */ + +/**** amalgamated original file "/src/pubsub/ua_pubsub_writer.c" ****/ + +/* This Sourc