Przeglądaj źródła

Merge remote-tracking branch 'origin/master' into connection_secureChannel

Conflicts:
	examples/src/networklayer.c
	examples/src/networklayer.h
	src/Makefile.am
	src/ua_services.h
	src/ua_services_attribute.c
	src/ua_transport_binary.h
	src/ua_transport_binary_secure.c
	src/ua_transport_binary_secure.h
FlorianPalm 11 lat temu
rodzic
commit
955b0a7fbe
59 zmienionych plików z 27034 dodań i 2157 usunięć
  1. 4 0
      .gitignore
  2. 2 1
      .travis.yml
  3. 0 1
      AUTHORS
  4. 0 1
      COPYING
  5. 0 0
      ChangeLog
  6. 1 2
      Makefile.am
  7. 0 1
      NEWS
  8. 0 0
      README
  9. 19 11
      README.md
  10. 1 0
      autogen.sh
  11. 18 17
      doc/Doxyfile.in
  12. 6 0
      doc/mainpage.dox
  13. 336 0
      doc/style/doxygen.css
  14. 20 0
      doc/style/footer.html
  15. 19 0
      doc/style/header.html
  16. 4 0
      doc/style/jquery-1.11.1.min.js
  17. 57 0
      doc/style/load-style.js
  18. 9 0
      examples/src/Makefile.am
  19. 23008 0
      examples/src/Opc.Ua.NodeSet2.xml
  20. 288 0
      examples/src/generateSam.c
  21. 0 1
      examples/src/networklayer.c
  22. 2 2
      examples/src/networklayer.h
  23. 1 1
      examples/src/opcuaServerMini.c
  24. 184 924
      examples/src/xml2ns0.c
  25. 166 113
      include/ua_basictypes.h
  26. 2 2
      include/ua_indexedList.h
  27. 31 11
      include/ua_list.h
  28. 24 78
      src/Makefile.am
  29. 3 6
      src/ua_application.c
  30. 1 1
      src/ua_application.h
  31. 266 250
      src/ua_basictypes.c
  32. 113 158
      src/ua_namespace.c
  33. 33 51
      src/ua_namespace.h
  34. 29 3
      src/ua_services.h
  35. 103 86
      src/ua_services_attribute.c
  36. 0 1
      src/ua_services_discovery.c
  37. 90 0
      src/ua_services_nodemanagement.c
  38. 22 0
      src/ua_services_view.c
  39. 1 0
      src/ua_stack_channel.c
  40. 0 2
      src/ua_stack_channel.h
  41. 1 0
      src/ua_stack_channel_manager.c
  42. 10 10
      src/ua_transport.h
  43. 27 28
      src/ua_transport_binary.c
  44. 9 0
      src/ua_transport_binary.h
  45. 2 46
      src/ua_transport_binary_secure.c
  46. 1 1
      src/ua_transport_binary_secure.h
  47. 0 6
      src/ua_transport_connection.c
  48. 1145 0
      src/ua_xml.c
  49. 117 0
      src/ua_xml.h
  50. 1 1
      tests/Makefile.am
  51. 16 24
      tests/check_builtin.c
  52. 161 5
      tests/check_namespace.c
  53. 65 0
      tests/check_services_view.c
  54. 409 108
      tests/check_stack.c
  55. 0 0
      tools/.coverity.sh
  56. 1 1
      tools/Makefile.am
  57. 134 139
      tools/generate_builtin.py
  58. 71 62
      tools/generate_namespace.py
  59. 1 2
      tools/indent.sh

+ 4 - 0
.gitignore

@@ -16,6 +16,7 @@
 *.pyc
 *.gcno
 *.gcda
+.dirstamp
 /bin
 m4
 /autom4te.cache
@@ -37,6 +38,9 @@ config.log
 /configure
 /missing
 /html
+/doc/html/*
+/doc/Doxyfile
+/doc/doxyfile.stamp
 *~
 GIT_REVISION
 SVN_REVISION

+ 2 - 1
.travis.yml

@@ -15,6 +15,7 @@ addons:
     build_command: make
     branch_pattern: coverity_scan
 before_install:
+- sudo add-apt-repository ppa:libreoffice/ppa -y
 - sudo apt-get update -qq
 - sudo apt-get install -qq build-essential subversion git autoconf libtool texinfo
   python-lxml graphviz doxygen
@@ -42,4 +43,4 @@ after_success:
    - cd ..
    - cd ..
    - rm -rf open62541
-   - ./.coverity.sh
+   - ./tools/.coverity.sh

+ 0 - 1
AUTHORS

@@ -1 +0,0 @@
-

+ 0 - 1
COPYING

@@ -1 +0,0 @@
-<Place your desired license here.>

+ 0 - 0
ChangeLog


+ 1 - 2
Makefile.am

@@ -28,5 +28,4 @@ endif
 if ENABLE_DOXYGEN
 	SUBS+= doc
 endif
-SUBDIRS = $(SUBS) examples/src	
-
+SUBDIRS = $(SUBS) examples/src	

+ 0 - 1
NEWS

@@ -1 +0,0 @@
-Sample NEWS file for OPCUAServer project.

+ 0 - 0
README


+ 19 - 11
README.md

@@ -7,12 +7,15 @@ An open-source communication stack implementation of OPC UA (OPC Unified Archite
 [![Build Status](https://travis-ci.org/acplt/open62541.png?branch=master)](https://travis-ci.org/acplt/open62541)
 [![Coverity Scan Build Status](https://scan.coverity.com/projects/1864/badge.svg)](https://scan.coverity.com/projects/1864)
 
+### Documentation
+Documentation is generated from Doxygen annotations in the source code. The current version can be accessed at http://acplt.github.io/open62541/doxygen/.
+
 
 ## Getting dependencies
 ### Ubuntu
 ##### Getting gcc toolchain:
 ```bash
-sudo apt-get install build-essential subversion git autoconf libtool texinfo
+sudo apt-get install build-essential subversion git autoconf libtool pkg-config texinfo
 ```
 ##### Getting python toolchain for the 62541 structures code generator:
 ```bash
@@ -20,7 +23,7 @@ sudo apt-get install python python-lxml
 ```
 ##### Getting additional libraries:
 ```bash
-sudo apt-get expat libexpat1-dev
+sudo apt-get install expat libexpat1-dev
 ```
 ##### Getting and installing *check* as unit test framework (http://check.sourceforge.net/):
 ```bash
@@ -57,6 +60,18 @@ $ make all
 * Copy gtk+/share/aclocal/*.m4 files to MinGW/share/aclocal
 * Merge grk+ folder and MinGW\msys\1.0\ folder
 
+##### Get expat
+* start MinGW Installation Manager
+* choose all Packages, mark mingw32-expat and install
+
+##### Get Python and lxml:
+* download Python at https://python.org/downloads
+* install the executable
+* add the install directory (e. g. "c:\python27") to your windows path variable 
+* restart mingw console
+* install lxml by either downloading and installing http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml (choose the version which fits    to your python installation) or by following the instructions
+  given here: http://lxml.de/installation.html
+
 ##### Get git (IMPORTANT: get 1.8.4, since 1.8.5.2 has a bug):
 * http://code.google.com/p/msysgit/downloads/detail?name=Git-1.8.4-preview20130916.exe&can=2&q=
 
@@ -67,19 +82,11 @@ $ make all
 $ svn checkout svn://svn.code.sf.net/p/check/code/trunk check-code
 $ cd check-code
 $ autoreconf --install
-$ ./configure --prefix=
+$ ./configure
 $ make
 $ make install
 ```
 
-##### Get Pyhton with lxml module
-* [TBD]
-
-## Clone open62541
-```bash
-$ git clone https://github.com/acplt/open62541.git
-```
-
 ## Building 
 * use autogen.sh only first time and whenever aclocal.m4 or configure.ac were modified
 ```bash
@@ -89,6 +96,7 @@ $ ./configure --enable-debug=yes
 $ make
 $ make check
 ```
+
 ### Configure Options 
 * --enable-debug=(yes|no|verbose) - omit/include debug code
 * --enable-multithreading - enable pthreads (for examples/src/opcuaServerMT)

+ 1 - 0
autogen.sh

@@ -1,4 +1,5 @@
 #!/bin/bash
 
 #Script to invoke creation of configure script
+touch COPYING NEWS README AUTHORS ChangeLog
 autoreconf -fi

+ 18 - 17
doc/Doxyfile.in

@@ -242,7 +242,7 @@ TCL_SUBST              =
 # members will be omitted, etc.
 # The default value is: NO.
 
-OPTIMIZE_OUTPUT_FOR_C  = NO
+OPTIMIZE_OUTPUT_FOR_C  = YES
 
 # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
 # Python sources only. Doxygen will then generate output that is more tailored
@@ -371,7 +371,7 @@ INLINE_GROUPED_CLASSES = NO
 # Man pages) or section (for LaTeX and RTF).
 # The default value is: NO.
 
-INLINE_SIMPLE_STRUCTS  = NO
+INLINE_SIMPLE_STRUCTS  = YES
 
 # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
 # enum is documented as struct, union, or enum with the name of the typedef. So
@@ -382,7 +382,7 @@ INLINE_SIMPLE_STRUCTS  = NO
 # types are typedef'ed and only the typedef is referenced, never the tag name.
 # The default value is: NO.
 
-TYPEDEF_HIDES_STRUCT   = NO
+TYPEDEF_HIDES_STRUCT   = YES
 
 # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
 # cache is used to resolve symbols given their name and scope. Since this can be
@@ -649,7 +649,7 @@ SHOW_FILES             = YES
 # Folder Tree View (if specified).
 # The default value is: YES.
 
-SHOW_NAMESPACES        = YES
+SHOW_NAMESPACES        = NO
 
 # The FILE_VERSION_FILTER tag can be used to specify a program or script that
 # doxygen should invoke to get the current version for each file (typically from
@@ -774,7 +774,7 @@ INPUT_ENCODING         = UTF-8
 # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
 # *.qsf, *.as and *.js.
 
-FILE_PATTERNS          =
+FILE_PATTERNS          = *.h *.dox
 
 # The RECURSIVE tag can be used to specify whether or not subdirectories should
 # be searched for input files as well.
@@ -805,7 +805,7 @@ EXCLUDE_SYMLINKS       = NO
 # Note that the wildcards are matched against the file with absolute path, so to
 # exclude all test directories for example use the pattern */test/*
 
-EXCLUDE_PATTERNS       =
+EXCLUDE_PATTERNS       = */cov-int/*
 
 # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
 # (namespaces, classes, functions, etc.) that should be excluded from the
@@ -994,7 +994,7 @@ ALPHABETICAL_INDEX     = YES
 # Minimum value: 1, maximum value: 20, default value: 5.
 # This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
 
-COLS_IN_ALPHA_INDEX    = 5
+COLS_IN_ALPHA_INDEX    = 3
 
 # In case all classes in a project start with a common prefix, all classes will
 # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
@@ -1046,7 +1046,7 @@ HTML_FILE_EXTENSION    = .html
 # of the possible markers and block names see the documentation.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_HEADER            =
+HTML_HEADER            = style/header.html
 
 # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
 # generated HTML page. If the tag is left blank doxygen will generate a standard
@@ -1056,7 +1056,7 @@ HTML_HEADER            =
 # that doxygen normally uses.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_FOOTER            =
+HTML_FOOTER            = style/footer.html
 
 # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
 # sheet that is used by each HTML page. It can be used to fine-tune the look of
@@ -1068,7 +1068,7 @@ HTML_FOOTER            =
 # obsolete.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_STYLESHEET        =
+HTML_STYLESHEET        = style/doxygen.css
 
 # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
 # defined cascading style sheet that is included after the standard style sheets
@@ -1089,7 +1089,8 @@ HTML_EXTRA_STYLESHEET  =
 # files will be copied as-is; there are no commands or markers available.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_EXTRA_FILES       =
+HTML_EXTRA_FILES       = style/jquery-1.11.1.min.js \
+                         style/load-style.js
 
 # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
 # will adjust the colors in the stylesheet and background images according to
@@ -1135,7 +1136,7 @@ HTML_TIMESTAMP         = YES
 # The default value is: NO.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_DYNAMIC_SECTIONS  = NO
+HTML_DYNAMIC_SECTIONS  = YES
 
 # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
 # shown in the various tree structured indices initially; the user can expand
@@ -1478,7 +1479,7 @@ MATHJAX_CODEFILE       =
 # The default value is: YES.
 # This tag requires that the tag GENERATE_HTML is set to YES.
 
-SEARCHENGINE           = YES
+SEARCHENGINE           = NO
 
 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
 # implemented using a web server instead of a web client using Javascript. There
@@ -1552,7 +1553,7 @@ EXTRA_SEARCH_MAPPINGS  =
 # If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
 # The default value is: YES.
 
-GENERATE_LATEX         = YES
+GENERATE_LATEX         = NO
 
 # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
 # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@@ -2025,7 +2026,7 @@ PERL_PATH              = /usr/bin/perl
 # powerful graphs.
 # The default value is: YES.
 
-CLASS_DIAGRAMS         = YES
+CLASS_DIAGRAMS         = NO
 
 # You can define message sequence charts within doxygen comments using the \msc
 # command. Doxygen will then run the mscgen tool (see:
@@ -2098,7 +2099,7 @@ DOT_FONTPATH           =
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
-CLASS_GRAPH            = YES
+CLASS_GRAPH            = NO
 
 # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
 # graph for each documented class showing the direct and indirect implementation
@@ -2107,7 +2108,7 @@ CLASS_GRAPH            = YES
 # The default value is: YES.
 # This tag requires that the tag HAVE_DOT is set to YES.
 
-COLLABORATION_GRAPH    = YES
+COLLABORATION_GRAPH    = NO
 
 # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
 # groups, showing the direct groups dependencies.

+ 6 - 0
doc/mainpage.dox

@@ -0,0 +1,6 @@
+/**
+\mainpage Open62541 Developer Documentation
+
+This file should contain some high-level description and pointers for further reading.
+
+*/

Plik diff jest za duży
+ 336 - 0
doc/style/doxygen.css


+ 20 - 0
doc/style/footer.html

@@ -0,0 +1,20 @@
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+  <ul>
+    $navpath
+    <li class="footer">$generatedby
+    <a href="http://www.doxygen.org/index.html">
+    <img class="footer" src="doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
+  </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<address class="footer"><small>
+$generatedby &#160;<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="doxygen.png" alt="doxygen"/>
+</a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+</body>
+</html>

+ 19 - 0
doc/style/header.html

@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
+<script type="text/javascript" src="dynsections.js"></script>
+<script type="text/javascript" src="load-style.js"></script>
+$treeview
+$search
+$mathjax
+<link href="doxygen.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+

Plik diff jest za duży
+ 4 - 0
doc/style/jquery-1.11.1.min.js


+ 57 - 0
doc/style/load-style.js

@@ -0,0 +1,57 @@
+$( document ).ready(function() {
+
+	$('#top > div > ul > li > a').wrapInner("<b></b>");
+
+	$("div.header").prepend("<h2></h2>");
+	$("div.header > h2").text($("div.title").text());
+	$("div.headertitle").remove();
+	$("#nav-path").remove();
+	
+	$("body").wrapInner("<div class='container'><div class='row'><div class='col-md-12'></div></div></div>");
+	$("ul.tablist").addClass("nav nav-pills nav-justified");
+	$("ul.tablist").css("margin-top", "0.5em");
+	$("ul.tablist").css("margin-bottom", "0.5em");
+	$("li.current").addClass("active");
+	$(".contents").wrapInner("<div class='panel panel-default' style='margin-top:1em;'><div class='panel-body'></div></div>");
+
+	$("iframe").attr("scrolling", "yes");
+	
+	$('img[src="ftv2ns.png"]').replaceWith('<span class="label label-danger">N</span> ');
+	$('img[src="ftv2cl.png"]').replaceWith('<span class="label label-danger">C</span> ');
+
+	// dirty workaround since doxygen 1.7 doesn't set table ids
+	$("table").each(function() {
+		if($(this).find("tbody > tr > td.indexkey").length > 0) {
+			$(this).addClass("table table-striped");
+		}
+	});
+	
+	$("table.params").addClass("table");
+	$("div.ingroups").wrapInner("<small></small>");
+	$("div.levels").css("margin", "0.5em");
+	$("div.levels > span").addClass("btn btn-default btn-xs");
+	$("div.levels > span").css("margin-right", "0.25em");
+	
+	$("table.directory").addClass("table table-striped");
+	$("div.summary > a").addClass("btn btn-default btn-xs");
+	$("table.fieldtable").addClass("table");
+	$(".fragment").addClass("well");
+	$(".memitem").addClass("panel panel-default");
+	$(".memproto").addClass("panel-heading");
+	$(".memdoc").addClass("panel-body");
+	$("span.mlabel").addClass("label label-info");
+	
+	$("table.memberdecls").addClass("table");
+	$("[class^=memitem]").addClass("active");
+	$("td.memSeparator").remove()
+	
+	$("div.ah").addClass("btn btn-default");
+	$("span.mlabels").addClass("pull-right");
+	$("table.mlabels").css("width", "100%")
+	$("td.mlabels-right").addClass("pull-right");
+
+	$("div.ttc").addClass("panel panel-info");
+	$("div.ttname").addClass("panel-heading");
+	$("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body");
+});
+

+ 9 - 0
examples/src/Makefile.am

@@ -5,6 +5,15 @@ __top_builddir__bin_xml2ns0_CFLAGS = -I$(top_builddir)/src -I$(top_builddir)/inc
 __top_builddir__bin_xml2ns0_LDADD = $(top_builddir)/lib/libopen62541.a $(GLOBAL_AM_LDADD)
 __top_builddir__bin_xml2ns0_LDFLAGS = -lexpat
 
+bin_PROGRAMS += $(top_builddir)/bin/generateSam 
+
+__top_builddir__bin_generateSam_SOURCES = generateSam.c
+__top_builddir__bin_generateSam_CFLAGS = -I$(top_builddir)/src -I$(top_builddir)/include $(GLOBAL_AM_CFLAGS)
+__top_builddir__bin_generateSam_LDADD = $(top_builddir)/lib/libopen62541.a $(GLOBAL_AM_LDADD)
+__top_builddir__bin_generateSam_LDFLAGS = -lexpat
+
+
+
 if MULTITHREADING
 bin_PROGRAMS += $(top_builddir)/bin/exampleServerMT 
 

Plik diff jest za duży
+ 23008 - 0
examples/src/Opc.Ua.NodeSet2.xml


+ 288 - 0
examples/src/generateSam.c

@@ -0,0 +1,288 @@
+/*
+ * xml2ns0.c
+ *
+ *  Created on: 21.04.2014
+ *      Author: mrt
+ */
+
+#include "ua_xml.h"
+#include <ctype.h> // tolower
+
+/** @brief we need a variable global to the module to make it possible for the visitors to access the namespace */
+static Namespace* theNamespace;
+
+UA_Int32 UA_Node_getParent(const UA_Node* node, const UA_Node** parent) {
+	UA_Int32 i = 0;
+	DBG(printf("// UA_Node_getParent - node={i=%d}",UA_NodeId_getIdentifier(&(node->nodeId))));
+	// FIXME: the data model is crap! we should have a single memory location which holds the parent NodeId
+	for (; i < node->referencesSize; i++ ) {
+		UA_Int32 refId = UA_NodeId_getIdentifier(&(node->references[i]->referenceTypeId));
+		UA_Int32 isInverse = node->references[i]->isInverse;
+		if (isInverse && (refId == 47 || refId == 46)) {
+			Namespace_Entry_Lock* lock = UA_NULL;
+			UA_Int32 retval;
+			retval = Namespace_get(theNamespace, &(node->references[i]->targetId.nodeId),parent,&lock);
+			Namespace_Entry_Lock_release(lock);
+			if (retval == UA_SUCCESS) {
+				DBG(printf(" has parent={i=%d}\n",UA_NodeId_getIdentifier(&((*parent)->nodeId))));
+			} else {
+				DBG(printf(" has non-existing parent={i=%d}\n",UA_NodeId_getIdentifier(&(node->references[i]->targetId.nodeId))));
+			}
+			return retval;
+		}
+	}
+	// there is no parent, we are root
+	DBG(printf(" is root\n"));
+	*parent = UA_NULL;
+	return UA_SUCCESS;
+}
+
+/** @brief recurse down to root and return root node */
+UA_Int32 UA_Node_getRoot(const UA_Node* node, const UA_Node** root) {
+	UA_Int32 retval = UA_SUCCESS;
+	const UA_Node* parent = UA_NULL;
+	if ( (retval = UA_Node_getParent(node,&parent)) == UA_SUCCESS ) {
+		if (parent != UA_NULL) {	// recurse down to root node
+			retval = UA_Node_getRoot(parent,root);
+		} else {					// node is root, terminate recursion
+			*root = node;
+		}
+	}
+	return retval;
+}
+
+/** @brief check if VariableNode needs a memory object. This is the
+ * case if the parent is of type object and the root is type object
+ **/
+_Bool UA_VariableNode_needsObject(const UA_VariableNode* node) {
+	const UA_Node* parent = UA_NULL;
+	if ( UA_Node_getParent((UA_Node*)node,&parent) == UA_SUCCESS ) {
+		if (parent == UA_NULL)
+			return UA_TRUE;
+		if (parent->nodeClass == UA_NODECLASS_OBJECT ) {
+			const UA_Node* root;
+			if (UA_Node_getRoot(parent,&root) == UA_SUCCESS)
+				if (root == UA_NULL || root->nodeClass == UA_NODECLASS_OBJECT )
+					return UA_TRUE;
+		}
+	}
+	return UA_FALSE;
+}
+
+/** @brief recurse down to root and get full qualified name */
+UA_Int32 UA_Node_getPath(const UA_Node* node, UA_list_List* list) {
+	UA_Int32 retval = UA_SUCCESS;
+	const UA_Node* parent = UA_NULL;
+	if ( (retval = UA_Node_getParent(node,&parent)) == UA_SUCCESS ) {
+		if (parent != UA_NULL) {
+			// recurse down to root node
+			UA_Int32 retval = UA_Node_getPath(parent,list);
+			// and add our own name when we come back
+			if (retval == UA_SUCCESS) {
+				UA_list_addPayloadToBack(list,(void*)&(node->browseName.name));
+				DBG(printf("// UA_Node_getPath - add id={i=%d},class=%d",UA_NodeId_getIdentifier(&(node->nodeId)),node->nodeClass));
+				DBG(UA_String_printf(",name=",&(node->browseName.name)));
+			}
+		} else {
+			// node is root, terminate recursion by adding own name
+			UA_list_addPayloadToBack(list,(void*)&node->browseName.name);
+			DBG(printf("// UA_Node_getPath - add id={i=%d},class=%d",UA_NodeId_getIdentifier(&(node->nodeId)),node->nodeClass));
+			DBG(UA_String_printf(",name=",&(node->browseName.name)));
+		}
+	}
+	return retval;
+}
+
+
+/** @brief some macros to lowercase the first character without copying around */
+#define F_cls "%c%.*s"
+#define LC_cls(str) tolower((str).data[0]), (str).length-1, &((str).data[1])
+
+void listPrintName(void * payload) {
+	UA_ByteString* name = (UA_ByteString*) payload;
+	if (name->length > 0) {
+		printf("_" F_cls, LC_cls(*name));
+	}
+}
+
+/** @brief declares all the top level objects in the server's application memory */
+void sam_declareAttribute(UA_Node const * node) {
+	if (node->nodeClass == UA_NODECLASS_VARIABLE && UA_VariableNode_needsObject((UA_VariableNode*)node)) {
+		UA_list_List list; UA_list_init(&list);
+		UA_Int32 retval = UA_Node_getPath(node,&list);
+		if (retval == UA_SUCCESS) {
+			UA_VariableNode* vn = (UA_VariableNode*) node;
+			printf("\t%s ", UA_[UA_ns0ToVTableIndex(vn->dataType.identifier.numeric)].name);
+			UA_list_iteratePayload(&list,listPrintName);
+			printf("; // i=%d\n", node->nodeId.identifier.numeric);
+		} else {
+			printf("// could not determine path for i=%d\n",node->nodeId.identifier.numeric);
+		}
+		UA_list_destroy(&list,UA_NULL);
+	}
+}
+
+/** @brief declares all the buffers for string variables
+ * FIXME: shall traverse down to the root object and create a unique name such as cstr_serverState_buildInfo_version
+ */
+void sam_declareBuffer(UA_Node const * node) {
+	if (node != UA_NULL && node->nodeClass == UA_NODECLASS_VARIABLE) {
+		UA_VariableNode* vn = (UA_VariableNode*) node;
+		switch (vn->dataType.identifier.numeric) {
+		case UA_BYTESTRING_NS0:
+		case UA_STRING_NS0:
+		case UA_LOCALIZEDTEXT_NS0:
+		case UA_QUALIFIEDNAME_NS0:
+		printf("UA_Byte cstr_" F_cls "[] = \"\"\n",LC_cls(vn->browseName.name));
+		break;
+		default:
+		break;
+		}
+	}
+}
+
+/** @brief assigns the c-strings to the ua type strings.
+ * FIXME: traverse down to top level objects and create a unique name such as cstr_serverState_buildInfo_version
+ */
+void sam_assignBuffer(UA_Node const * node) {
+	if (node != UA_NULL && node->nodeClass == UA_NODECLASS_VARIABLE) {
+		UA_VariableNode* vn = (UA_VariableNode*) node;
+		switch (vn->dataType.identifier.numeric) {
+		case UA_BYTESTRING_NS0:
+		case UA_STRING_NS0:
+		printf("\tSAM_ASSIGN_CSTRING(cstr_" F_cls ",sam." F_cls ");\n",LC_cls(vn->browseName.name),LC_cls(vn->browseName.name));
+		break;
+		case UA_LOCALIZEDTEXT_NS0:
+		printf("\tSAM_ASSIGN_CSTRING(cstr_" F_cls ",sam." F_cls ".text);\n",LC_cls(vn->browseName.name),LC_cls(vn->browseName.name));
+		break;
+		case UA_QUALIFIEDNAME_NS0:
+		printf("\tSAM_ASSIGN_CSTRING(cstr_" F_cls ",sam." F_cls ".name);\n",LC_cls(vn->browseName.name),LC_cls(vn->browseName.name));
+		break;
+		default:
+		break;
+		}
+	}
+}
+
+void sam_attachToNamespace(UA_Node const * node) {
+	if (node != UA_NULL && node->nodeClass == UA_NODECLASS_VARIABLE) {
+		UA_VariableNode* vn = (UA_VariableNode*) node;
+		printf("\tsam_attach(ns,%d,%s,&sam." F_cls ");\n",node->nodeId.identifier.numeric,UA_[UA_ns0ToVTableIndex(vn->dataType.identifier.numeric)].name, LC_cls(vn->browseName.name));
+	}
+}
+
+UA_Int32 Namespace_getNumberOfComponents(Namespace const * ns, UA_NodeId const * id, UA_Int32* number) {
+	UA_Int32 retval = UA_SUCCESS;
+	UA_Node const * node;
+	if ((retval = Namespace_get(ns,id,&node,UA_NULL)) != UA_SUCCESS)
+		return retval;
+	if (node == UA_NULL)
+		return UA_ERR_INVALID_VALUE;
+	UA_Int32 i, n;
+	for (i = 0, n = 0; i < node->referencesSize; i++ ) {
+		if (node->references[i]->referenceTypeId.identifier.numeric == 47 && node->references[i]->isInverse != UA_TRUE) {
+			n++;
+		}
+	}
+	*number = n;
+	return retval;
+}
+
+UA_Int32 Namespace_getComponent(Namespace const * ns, UA_NodeId const * id, UA_Int32 idx, UA_NodeId** result) {
+	UA_Int32 retval = UA_SUCCESS;
+
+	UA_Node const * node;
+	if ((retval = Namespace_get(ns,id,&node,UA_NULL)) != UA_SUCCESS)
+		return retval;
+
+	UA_Int32 i, n;
+	for (i = 0, n = 0; i < node->referencesSize; i++ ) {
+		if (node->references[i]->referenceTypeId.identifier.numeric == 47 && node->references[i]->isInverse != UA_TRUE) {
+			n++;
+			if (n == idx) {
+				*result = &(node->references[i]->targetId.nodeId);
+				return retval;
+			}
+		}
+	}
+	return UA_ERR_INVALID_VALUE;
+}
+
+
+UA_Int32 UAX_NodeId_encodeBinaryByMetaData(Namespace const * ns, UA_NodeId const * id, UA_Int32* pos, UA_ByteString *dst) {
+	UA_Int32 i, retval = UA_SUCCESS;
+	if (UA_NodeId_isBasicType(id)) {
+		UA_Node const * result;
+		Namespace_Entry_Lock* lock;
+		if ((retval = Namespace_get(ns,id,&result,&lock)) == UA_SUCCESS)
+			UA_Variant_encodeBinary(&((UA_VariableNode *) result)->value,pos,dst);
+	} else {
+		UA_Int32 nComp = 0;
+		if ((retval = Namespace_getNumberOfComponents(ns,id,&nComp)) == UA_SUCCESS) {
+			for (i=0; i < nComp; i++) {
+				UA_NodeId* comp = UA_NULL;
+				Namespace_getComponent(ns,id,i,&comp);
+				UAX_NodeId_encodeBinaryByMetaData(ns,comp, pos, dst);
+			}
+		}
+	}
+	return retval;
+}
+
+UA_Int32 UAX_NodeId_encodeBinary(Namespace const * ns, UA_NodeId const * id, UA_Int32* pos, UA_ByteString *dst) {
+	UA_Int32 retval = UA_SUCCESS;
+	UA_Node const * node;
+	Namespace_Entry_Lock* lock;
+
+	if ((retval = Namespace_get(ns,id,&node,&lock)) == UA_SUCCESS) {
+		if (node->nodeClass == UA_NODECLASS_VARIABLE) {
+			retval = UA_Variant_encodeBinary(&((UA_VariableNode*) node)->value,pos,dst);
+		}
+		Namespace_Entry_Lock_release(lock);
+	}
+	return retval;
+}
+
+
+/** @ brief poor man's text template processor
+ * for p in patterns: print p.s, iterate over namespace with p.v */
+typedef struct pattern {
+		char* s;
+		Namespace_nodeVisitor v;
+} pattern;
+
+pattern p[] = {
+{ "/** server application memory - generated but manually adapted */\n",UA_NULL },
+{ "#define SAM_ASSIGN_CSTRING(src,dst) do { dst.length = strlen(src)-1; dst.data = (UA_Byte*) src; } while(0)\n",UA_NULL },
+{ "struct sam {\n", sam_declareAttribute },
+{ "} sam;\n", UA_NULL },
+{ UA_NULL, sam_declareBuffer },
+{ "void sam_init(Namespace* ns) {\n", sam_assignBuffer },
+{ UA_NULL, sam_attachToNamespace },
+{ "}\n", UA_NULL },
+{UA_NULL, UA_NULL} // terminal node : both elements UA_NULL
+};
+
+int main(int argc, char** argv) {
+	if (argc != 2) {
+		printf("usage: %s filename\n",argv[0]);
+	} else {
+		Namespace* ns;
+		if (Namespace_loadFromFile(&ns,0,"ROOT",argv[1]) != UA_SUCCESS) {
+			printf("error loading file {%s}\n", argv[1]);
+		} else {
+			theNamespace = ns;
+			for (pattern* pi = &p[0]; pi->s != UA_NULL || pi->v != UA_NULL; ++pi) {
+				if (pi->s) {
+					printf("%s",pi->s);
+				}
+				if (pi->v) {
+					Namespace_iterate(ns, pi->v);
+				}
+			}
+			// FIXME: crashes with a seg fault
+			// Namespace_delete(ns);
+		}
+	}
+	return 0;
+}

+ 0 - 1
examples/src/networklayer.c

@@ -175,7 +175,6 @@ void* NL_TCP_readerThread(NL_Connection *c) {
 	pthread_exit(UA_NULL);
 }
 #endif
-
 /** write message provided in the gather buffers to a tcp transport layer connection */
 UA_Int32 NL_TCP_writer(UA_Int32 connectionHandle, UA_ByteString const * const * gather_buf, UA_UInt32 gather_len) {
 

+ 2 - 2
examples/src/networklayer.h

@@ -25,7 +25,7 @@ enum NL_CONNECTIONTYPE_enum {
 	NL_CONNECTIONTYPE_TCPV6 = 1,
 };
 
-typedef struct T_NL_Description {
+typedef struct NL_Description {
 	UA_Int32 encoding;
 	UA_Int32 connectionType;
 	UA_Int32 maxConnections;
@@ -34,7 +34,7 @@ typedef struct T_NL_Description {
 
 extern NL_Description NL_Description_TcpBinary;
 
-typedef struct T_NL_data {
+typedef struct NL_data {
 	NL_Description* tld;
 	UA_String endpointUrl;
 	UA_list_List connections;

+ 1 - 1
examples/src/opcuaServerMini.c

@@ -219,7 +219,7 @@ UA_Int32 myProcess(TL_Connection* connection, const UA_ByteString* msg) {
 }
 
 /** write message provided in the gather buffers to a tcp transport layer connection */
-UA_Int32 myWriter(struct TL_Connection_T const * c, UA_ByteString const * const * gather_buf, UA_UInt32 gather_len) {
+UA_Int32 myWriter(struct TL_Connection const * c, UA_ByteString const * const * gather_buf, UA_UInt32 gather_len) {
 
 	struct iovec iov[gather_len];
 	UA_UInt32 total_len = 0;

Plik diff jest za duży
+ 184 - 924
examples/src/xml2ns0.c


+ 166 - 113
include/ua_basictypes.h

@@ -1,10 +1,3 @@
-/*
- * ua_basictypes.h
- *
- *  Created on: 13.03.2014
- *      Author: mrt
- */
-
 #ifndef OPCUA_BASICTYPES_H_
 #define OPCUA_BASICTYPES_H_
 
@@ -36,14 +29,12 @@ typedef int64_t UA_Int64;
 typedef uint64_t UA_UInt64;
 typedef float UA_Float;
 typedef double UA_Double;
+
 /* ByteString - Part: 6, Chapter: 5.2.2.7, Page: 17 */
-typedef struct T_UA_ByteString
-{
+typedef struct UA_ByteString {
 	UA_Int32 	length;
 	UA_Byte*	data;
-}
-UA_ByteString;
-
+} UA_ByteString;
 
 /* Function return values */
 #define UA_SUCCESS 0
@@ -91,10 +82,19 @@ UA_Int32 UA_Array_init(void **p,UA_Int32 noElements, UA_Int32 type);
 UA_Int32 UA_Array_new(void ***p,UA_Int32 noElements, UA_Int32 type);
 UA_Int32 UA_Array_copy(void const * const *src,UA_Int32 noElements, UA_Int32 type, void ***dst);
 
+/* XML prelimiaries */
+struct XML_Stack;
+typedef char const * const XML_Attr;
+typedef char const * cstring;
+#define XML_STACK_MAX_DEPTH 10
+#define XML_STACK_MAX_CHILDREN 40
+typedef UA_Int32 (*XML_decoder)(struct XML_Stack* s, XML_Attr* attr, void* dst, UA_Boolean isStart);
+
 #define UA_TYPE_METHOD_PROTOTYPES(TYPE) \
 	UA_Int32 TYPE##_calcSize(TYPE const * ptr);							\
 	UA_Int32 TYPE##_encodeBinary(TYPE const * src, UA_Int32* pos, UA_ByteString * dst);	\
 	UA_Int32 TYPE##_decodeBinary(UA_ByteString const * src, UA_Int32* pos, TYPE * dst);	\
+	UA_Int32 TYPE##_decodeXML(struct XML_Stack* s, XML_Attr* attr, TYPE* dst, UA_Boolean isStart); \
 	UA_Int32 TYPE##_delete(TYPE * p);									\
 	UA_Int32 TYPE##_deleteMembers(TYPE * p);							\
 	UA_Int32 TYPE##_init(TYPE * p);										\
@@ -122,13 +122,12 @@ UA_Int32 TYPE##_delete(TYPE *p) { \
 }
 
 #define UA_TYPE_METHOD_COPY(TYPE) \
-UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst){ \
+UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst) { \
 	UA_Int32 retval = UA_SUCCESS; \
 	retval |= UA_memcpy(dst, src, TYPE##_calcSize(UA_NULL)); \
 	return retval; \
 }
 
-
 #define UA_TYPE_METHOD_DELETEMEMBERS_NOACTION(TYPE) \
 UA_Int32 TYPE##_deleteMembers(TYPE * p) { return UA_SUCCESS; }
 
@@ -140,32 +139,45 @@ UA_Int32 TYPE##_decodeBinary(UA_ByteString const * src, UA_Int32* pos, TYPE *dst
 	return TYPE_AS##_decodeBinary(src,pos,(TYPE_AS*) dst); \
 }
 
+#define UA_TYPE_METHOD_DECODEXML_NOTIMPL(TYPE) \
+	UA_Int32 TYPE##_decodeXML(XML_Stack* s, XML_Attr* attr, TYPE* dst, _Bool isStart) { \
+		DBG_VERBOSE(printf(#TYPE "_decodeXML entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); \
+		return UA_ERR_NOT_IMPLEMENTED;\
+	}
+
+#define UA_TYPE_METHOD_DECODEXML_AS(TYPE,TYPE_AS) \
+	UA_Int32 TYPE##_decodeXML(struct XML_Stack* s, XML_Attr* attr, TYPE* dst, _Bool isStart) { \
+		return TYPE_AS##_decodeXML(s,attr,(TYPE_AS*) dst,isStart); \
+	}
+
 #define UA_TYPE_METHOD_ENCODEBINARY_AS(TYPE,TYPE_AS) \
 UA_Int32 TYPE##_encodeBinary(TYPE const * src, UA_Int32* pos, UA_ByteString *dst) { \
 	return TYPE_AS##_encodeBinary((TYPE_AS*) src,pos,dst); \
 }
 
 #define UA_TYPE_METHOD_INIT_AS(TYPE, TYPE_AS) \
-UA_Int32 TYPE##_init(TYPE * p){ \
+UA_Int32 TYPE##_init(TYPE * p) { \
 	return TYPE_AS##_init((TYPE_AS*)p); \
 }
 #define UA_TYPE_METHOD_COPY_AS(TYPE, TYPE_AS) \
 UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst) {return TYPE_AS##_copy((TYPE_AS*) src,(TYPE_AS*)dst); \
 }
 
+#define UA_TYPE_METHOD_PROTOTYPES_AS_WOXML(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_CALCSIZE_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_ENCODEBINARY_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_DECODEBINARY_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_DELETE_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_DELETEMEMBERS_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_INIT_AS(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_COPY_AS(TYPE, TYPE_AS)
 
 #define UA_TYPE_METHOD_PROTOTYPES_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_CALCSIZE_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_ENCODEBINARY_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_DECODEBINARY_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_DELETE_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_DELETEMEMBERS_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_INIT_AS(TYPE, TYPE_AS) \
-UA_TYPE_METHOD_COPY_AS(TYPE, TYPE_AS)
-
+	UA_TYPE_METHOD_PROTOTYPES_AS_WOXML(TYPE, TYPE_AS) \
+	UA_TYPE_METHOD_DECODEXML_AS(TYPE, TYPE_AS)
 
 #define UA_TYPE_METHOD_NEW_DEFAULT(TYPE) \
-UA_Int32 TYPE##_new(TYPE ** p){ \
+UA_Int32 TYPE##_new(TYPE ** p) { \
 	UA_Int32 retval = UA_SUCCESS;\
 	retval |= UA_alloc((void**)p, TYPE##_calcSize(UA_NULL));\
 	retval |= TYPE##_init(*p);\
@@ -173,15 +185,13 @@ UA_Int32 TYPE##_new(TYPE ** p){ \
 }
 
 #define UA_TYPE_METHOD_INIT_DEFAULT(TYPE) \
-UA_Int32 TYPE##_init(TYPE * p){ \
+UA_Int32 TYPE##_init(TYPE * p) { \
 	if(p==UA_NULL)return UA_ERROR;\
 	*p = (TYPE)0;\
 	return UA_SUCCESS;\
 }
 //#define UA_TYPE_COPY_METHOD_PROTOTYPE(TYPE) \  UA_Int32 TYPE##_copy(TYPE const *src, TYPE *dst);
 
-
-
 /*** Prototypes for basic types **/
 UA_TYPE_METHOD_PROTOTYPES (UA_Boolean)
 UA_TYPE_METHOD_PROTOTYPES (UA_Byte)
@@ -194,6 +204,7 @@ UA_TYPE_METHOD_PROTOTYPES (UA_Int64)
 UA_TYPE_METHOD_PROTOTYPES (UA_UInt64)
 UA_TYPE_METHOD_PROTOTYPES (UA_Float)
 UA_TYPE_METHOD_PROTOTYPES (UA_Double)
+
 /**
 * StatusCodeBinaryEncoding
 * Part: 6
@@ -210,43 +221,14 @@ UA_TYPE_METHOD_PROTOTYPES (UA_StatusCode)
 typedef float UA_IntegerId;
 UA_TYPE_METHOD_PROTOTYPES (UA_IntegerId)
 
-typedef struct T_UA_VTable {
-	UA_UInt32 ns0Id;
-	UA_Int32 (*calcSize)(void const * ptr);
-	UA_Int32 (*decodeBinary)(UA_ByteString const * src, UA_Int32* pos, void* dst);
-	UA_Int32 (*encodeBinary)(void const * src, UA_Int32* pos, UA_ByteString* dst);
-	UA_Int32 (*init)(void * p);
-	UA_Int32 (*new)(void ** p);
-	UA_Int32 (*copy)(void const *src,void *dst);
-	UA_Int32 (*delete)(void * p);
-	UA_Byte* name;
-} UA_VTable;
-
-/* VariantBinaryEncoding - Part: 6, Chapter: 5.2.2.16, Page: 22 */
-enum UA_VARIANT_ENCODINGMASKTYPE_enum
-{
-	UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3F,	// bits 0:5
-	UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS = (0x01 << 6), // bit 6
-	UA_VARIANT_ENCODINGMASKTYPE_ARRAY = ( 0x01 << 7) // bit 7
-};
-
-typedef struct T_UA_Variant {
-	UA_VTable* vt;		// internal entry into vTable
-	UA_Byte encodingMask; 	// Type of UA_Variant_EncodingMaskType_enum
-	UA_Int32 arrayLength;	// total number of elements
-	UA_Int32 arrayDimensionsLength;
-	UA_Int32 **arrayDimensions;
-	void** data;
-} UA_Variant;
-UA_TYPE_METHOD_PROTOTYPES (UA_Variant)
-
-/* String - Part: 6, Chapter: 5.2.2.4, Page: 16 */
-typedef struct T_UA_String
-{
+/** @brief String Object
+ *
+ *  String - Part: 6, Chapter: 5.2.2.4, Page: 16
+ */
+typedef struct UA_String {
 	UA_Int32 	length;
 	UA_Byte*	data;
-}
-UA_String;
+} UA_String;
 UA_TYPE_METHOD_PROTOTYPES (UA_String)
 //UA_Int32 UA_String_copy(UA_String const * src, UA_String* dst);
 UA_Int32 UA_String_copycstring(char const * src, UA_String* dst);
@@ -263,19 +245,17 @@ UA_Int32 UA_ByteString_compare(const UA_ByteString *string1, const UA_ByteString
 UA_Int32 UA_ByteString_newMembers(UA_ByteString* p, UA_Int32 length);
 extern UA_ByteString UA_ByteString_securityPoliceNone;
 
-/** LocalizedTextBinaryEncoding - Part: 6, Chapter: 5.2.2.14, Page: 21 */
-enum UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_enum
-{
+/* LocalizedTextBinaryEncoding - Part: 6, Chapter: 5.2.2.14, Page: 21 */
+enum UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_enum {
 	UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE = 0x01,
 	UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT = 0x02
 };
-typedef struct T_UA_LocalizedText
-{
+
+typedef struct UA_LocalizedText {
 	UA_Byte encodingMask;
 	UA_String locale;
 	UA_String text;
-}
-UA_LocalizedText;
+} UA_LocalizedText;
 UA_TYPE_METHOD_PROTOTYPES (UA_LocalizedText)
 
 UA_Int32 UA_LocalizedText_copycstring(char const * src, UA_LocalizedText* dst);
@@ -284,8 +264,7 @@ void UA_ByteString_printx(char* label, const UA_ByteString* string);
 void UA_ByteString_printx_hex(char* label, const UA_ByteString* string);
 
 /* GuidType - Part: 6, Chapter: 5.2.2.6 Page: 17 */
-typedef struct T_UA_Guid
-{
+typedef struct UA_Guid {
 	UA_UInt32 data1;
 	UA_UInt16 data2;
 	UA_UInt16 data3;
@@ -299,8 +278,7 @@ typedef UA_Int64 UA_DateTime; //100 nanosecond resolution
 UA_TYPE_METHOD_PROTOTYPES (UA_DateTime)
 
 UA_DateTime UA_DateTime_now();
-typedef struct T_UA_DateTimeStruct
-{
+typedef struct UA_DateTimeStruct {
 	UA_Int16 nanoSec;
 	UA_Int16 microSec;
 	UA_Int16 milliSec;
@@ -315,77 +293,154 @@ UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime time);
 UA_Int32 UA_DateTime_difference_ms(UA_DateTime time1, UA_DateTime time2);
 UA_Int32 UA_DateTime_toString(UA_DateTime time, UA_String* timeString);
 
-
-typedef struct T_UA_NodeId
-{
+typedef struct UA_NodeId {
 	UA_Byte   encodingByte; //enum BID_NodeIdEncodingValuesType
 	UA_UInt16 namespace;
-
-    union
-    {
+    union {
         UA_UInt32 numeric;
         UA_String string;
         UA_Guid guid;
         UA_ByteString byteString;
-    }
-    identifier;
+    } identifier;
 } UA_NodeId;
 UA_TYPE_METHOD_PROTOTYPES (UA_NodeId)
 
 UA_Int32 UA_NodeId_compare(const UA_NodeId *n1, const UA_NodeId *n2);
 void UA_NodeId_printf(char* label, const UA_NodeId* node);
+UA_Boolean UA_NodeId_isNull(const UA_NodeId* p);
+UA_Int16 UA_NodeId_getNamespace(UA_NodeId const * id);
+UA_Int16 UA_NodeId_getIdentifier(UA_NodeId const * id);
+_Bool UA_NodeId_isBasicType(UA_NodeId const * id);
+
 
-/** XmlElement - Part: 6, Chapter: 5.2.2.8, Page: 17 */
-typedef struct T_UA_XmlElement
-{
+/* XmlElement - Part: 6, Chapter: 5.2.2.8, Page: 17 */
+typedef struct UA_XmlElement {
 	//TODO Überlegung ob man es direkt als ByteString speichert oder als String
 	UA_ByteString data;
 } UA_XmlElement;
 UA_TYPE_METHOD_PROTOTYPES (UA_XmlElement)
 
-
 /* ExpandedNodeId - Part: 6, Chapter: 5.2.2.10, Page: 19 */
 // 62541-6 Chapter 5.2.2.9, Table 5
 #define UA_NODEIDTYPE_NAMESPACE_URI_FLAG 0x80
 #define UA_NODEIDTYPE_SERVERINDEX_FLAG   0x40
 #define UA_NODEIDTYPE_MASK (~(UA_NODEIDTYPE_NAMESPACE_URI_FLAG | UA_NODEIDTYPE_SERVERINDEX_FLAG))
-typedef struct T_UA_ExpandedNodeId
-{
+typedef struct UA_ExpandedNodeId {
 	UA_NodeId nodeId;
 	UA_String namespaceUri;
 	UA_UInt32 serverIndex;
-}
-UA_ExpandedNodeId;
+} UA_ExpandedNodeId;
 UA_TYPE_METHOD_PROTOTYPES(UA_ExpandedNodeId)
+UA_Boolean UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId* p);
 
-
+/* IdentifierType */
 typedef UA_Int32 UA_IdentifierType;
 UA_TYPE_METHOD_PROTOTYPES(UA_IdentifierType)
 
-
 /* ExtensionObjectBinaryEncoding - Part: 6, Chapter: 5.2.2.15, Page: 21 */
-typedef struct T_UA_ExtensionObject {
+typedef struct UA_ExtensionObject {
 	UA_NodeId typeId;
 	UA_Byte encoding; //Type of the enum UA_ExtensionObjectEncodingMaskType
-	UA_ByteString body;
+	UA_ByteString body; // contains either the bytestring or a pointer to the memory-object
 } UA_ExtensionObject;
 UA_TYPE_METHOD_PROTOTYPES(UA_ExtensionObject)
 
-enum UA_ExtensionObject_EncodingMaskType_enum
-{
-	UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED = 	0x00,
+enum UA_ExtensionObject_EncodingMaskType_enum {
+	UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED =   0x00,
 	UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING = 	0x01,
-	UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISXML = 	0x02
+	UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISXML =         0x02
 };
 
 /* QualifiedNameBinaryEncoding - Part: 6, Chapter: 5.2.2.13, Page: 20 */
-typedef struct T_UA_QualifiedName {
+typedef struct UA_QualifiedName {
 	UA_UInt16 namespaceIndex;
-	UA_UInt16 reserved;
+	/*UA_UInt16 reserved; removed by Sten since unclear origin*/
 	UA_String name;
 } UA_QualifiedName;
 UA_TYPE_METHOD_PROTOTYPES(UA_QualifiedName)
 
+/* XML Decoding */
+
+/** @brief A readable shortcut for NodeIds. A list of aliases is intensively used in the namespace0-xml-files */
+typedef struct UA_NodeSetAlias {
+	UA_String alias;
+	UA_String value;
+} UA_NodeSetAlias;
+UA_TYPE_METHOD_PROTOTYPES (UA_NodeSetAlias)
+
+/** @brief UA_NodeSetAliases - a list of aliases */
+typedef struct UA_NodeSetAliases {
+	UA_Int32 size;
+	UA_NodeSetAlias** aliases;
+} UA_NodeSetAliases;
+UA_TYPE_METHOD_PROTOTYPES (UA_NodeSetAliases)
+
+typedef struct XML_child {
+	cstring name;
+	UA_Int32 length;
+	UA_Int32 type;
+	XML_decoder elementHandler;
+	void* obj;
+} XML_child;
+
+typedef struct XML_Parent {
+	cstring name;
+	int textAttribIdx; // -1 - not set
+	cstring textAttrib;
+	int activeChild; // -1 - no active child
+	int len; // -1 - empty set
+	XML_child children[XML_STACK_MAX_CHILDREN];
+} XML_Parent;
+
+typedef struct XML_Stack {
+	int depth;
+	XML_Parent parent[XML_STACK_MAX_DEPTH];
+	UA_Int32 nsid;
+	UA_NodeSetAliases* aliases; // shall point to the aliases of the NodeSet after reading
+} XML_Stack;
+
+typedef struct UA_VTable {
+	UA_UInt32 ns0Id;
+	UA_Int32 (*calcSize)(void const * ptr);
+	UA_Int32 (*decodeBinary)(UA_ByteString const * src, UA_Int32* pos, void* dst);
+	UA_Int32 (*encodeBinary)(void const * src, UA_Int32* pos, UA_ByteString* dst);
+	UA_Int32 (*decodeXML)(XML_Stack* s, XML_Attr* attr, void* dst, UA_Boolean isStart);
+	UA_Int32 (*init)(void * p);
+	UA_Int32 (*new)(void ** p);
+	UA_Int32 (*copy)(void const *src,void *dst);
+	UA_Int32 (*delete)(void * p);
+	UA_UInt32 memSize; // size of the struct only in memory (no dynamic components)
+	UA_Byte* name;
+} UA_VTable;
+
+/* VariantBinaryEncoding - Part: 6, Chapter: 5.2.2.16, Page: 22 */
+enum UA_VARIANT_ENCODINGMASKTYPE_enum {
+	UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3F,	// bits 0:5
+	UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS =  (0x01 << 6), // bit 6
+	UA_VARIANT_ENCODINGMASKTYPE_ARRAY =       (0x01 << 7) // bit 7
+};
+
+typedef struct UA_Variant {
+	UA_VTable* vt;		// internal entry into vTable
+	UA_Byte encodingMask; 	// Type of UA_Variant_EncodingMaskType_enum
+	UA_Int32 arrayLength;	// total number of elements
+	UA_Int32 arrayDimensionsLength;
+	UA_Int32 **arrayDimensions;
+	void** data;
+} UA_Variant;
+UA_TYPE_METHOD_PROTOTYPES (UA_Variant)
+
+UA_Int32 UA_Variant_copySetValue(UA_Variant *v, UA_Int32 type, const void* data);
+UA_Int32 UA_Variant_copySetArray(UA_Variant *v, UA_Int32 type_id, UA_Int32 arrayLength, UA_UInt32 elementSize, const void* array);
+
+/**
+   @brief Functions UA_Variant_borrowSetValue and ..Array allow to define
+ variants whose payload will not be deleted. This is achieved by a second
+ vtable. The functionality can be used e.g. when UA_VariableNodes point into a
+ "father" structured object that is stored in an UA_VariableNode itself. */
+UA_Int32 UA_Variant_borrowSetValue(UA_Variant *v, UA_Int32 type, const void* data); // Take care not to free the data before the variant.
+UA_Int32 UA_Variant_borrowSetArray(UA_Variant *v, UA_Int32 type, UA_Int32 arrayLength, const void* data); // Take care not to free the data before the variant.
+
 /* DataValue - Part: 6, Chapter: 5.2.2.17, Page: 23 */
 typedef struct UA_DataValue {
 	UA_Byte encodingMask;
@@ -399,10 +454,9 @@ typedef struct UA_DataValue {
 UA_TYPE_METHOD_PROTOTYPES(UA_DataValue)
 
 /** 62541-6, §5.2.2.17, Table 15 */
-enum UA_DATAVALUE_ENCODINGMASKTYPE_enum
-{
-	UA_DATAVALUE_ENCODINGMASK_VARIANT = 	0x01,
-	UA_DATAVALUE_ENCODINGMASK_STATUSCODE = 	0x02,
+enum UA_DATAVALUE_ENCODINGMASKTYPE_enum {
+	UA_DATAVALUE_ENCODINGMASK_VARIANT = 	        0x01,
+	UA_DATAVALUE_ENCODINGMASK_STATUSCODE = 	        0x02,
 	UA_DATAVALUE_ENCODINGMASK_SOURCETIMESTAMP = 	0x04,
 	UA_DATAVALUE_ENCODINGMASK_SERVERTIMESTAMP = 	0x08,
 	UA_DATAVALUE_ENCODINGMASK_SOURCEPICOSECONDS = 	0x10,
@@ -410,7 +464,7 @@ enum UA_DATAVALUE_ENCODINGMASKTYPE_enum
 };
 
 /* DiagnosticInfo - Part: 6, Chapter: 5.2.2.12, Page: 20 */
-typedef struct T_UA_DiagnosticInfo {
+typedef struct UA_DiagnosticInfo {
 	UA_Byte encodingMask; //Type of the Enum UA_DIAGNOSTICINFO_ENCODINGMASKTYPE
 	UA_Int32 symbolicId;
 	UA_Int32 namespaceUri;
@@ -418,18 +472,17 @@ typedef struct T_UA_DiagnosticInfo {
 	UA_Int32 locale;
 	UA_String additionalInfo;
 	UA_StatusCode innerStatusCode;
-	struct T_UA_DiagnosticInfo* innerDiagnosticInfo;
+	struct UA_DiagnosticInfo* innerDiagnosticInfo;
 } UA_DiagnosticInfo;
 UA_TYPE_METHOD_PROTOTYPES(UA_DiagnosticInfo)
 
-enum UA_DIAGNOSTICINFO_ENCODINGMASKTYPE_enum
-{
-	UA_DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID = 			0x01,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE = 			0x02,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT = 		0x04,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALE = 				0x08,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO = 		0x10,
-	UA_DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE = 	0x20,
+enum UA_DIAGNOSTICINFO_ENCODINGMASKTYPE_enum {
+	UA_DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID = 		 0x01,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE = 		     0x02,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT = 	     0x04,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALE = 			 0x08,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO =      0x10,
+	UA_DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE =     0x20,
 	UA_DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO = 0x40
 };
 

+ 2 - 2
include/ua_indexedList.h

@@ -8,8 +8,8 @@
 /*
  * Integer Indexed List
  */
-typedef struct T_UA_indexedList_Element {
-	struct T_UA_list_Element* father;
+typedef struct UA_indexedList_Element {
+	struct UA_list_Element* father;
 	UA_Int32 index;
 	void* payload;
 }UA_indexedList_Element;

+ 31 - 11
include/ua_list.h

@@ -2,23 +2,43 @@
 #define UA_LIST_H_
 
 #include "opcua.h"
-
-/*
- * Double Linked Lists
- */
+#include <stddef.h> /* Needed for sys/queue.h */
+#include <sys/queue.h>
+
+
+/**********************/
+/* Singly Linked List */
+/**********************/
+
+#define UA_SLIST_HEAD(name, type) SLIST_HEAD(name, type)
+#define UA_SLIST_HEAD_INITIALIZER(head) SLIST_HEAD_INITILIZER(head)
+#define UA_SLIST_ENTRY(type) SLIST_ENTRY(type)
+#define UA_SLIST_INIT(head) SLIST_INIT(head)
+#define UA_SLIST_INSERT_AFTER(slistelm, elm, field) SLIST_INSERT_AFTER(slistelm, elm, field)
+#define UA_SLIST_INSERT_HEAD(head, elm, field) SLIST_INSERT_HEAD(head, elm, field)
+#define UA_SLIST_REMOVE_HEAD(head, field) SLIST_REMOVE_HEAD(head, field)
+#define UA_SLIST_REMOVE(head, elm, type, field) SLIST_REMOVE(head, elm, type, field)
+#define UA_SLIST_FOREACH(var, head, field) SLIST_FOREACH(var, head, field)
+#define UA_SLIST_EMPTY(head) SLIST_EMPTY(head)
+#define UA_SLIST_FIRST(head) SLIST_FIRST(head)
+#define UA_SLIST_NEXT(elm, field) SLIST_NEXT(elm, field)
+
+/**********************/
+/* Doubly Linked List */
+/**********************/
 
 typedef void (*UA_list_PayloadVisitor)(void* payload);
 
-typedef struct T_UA_list_Element {
-	struct T_UA_list_List* father;
+typedef struct UA_list_Element {
+	struct UA_list_List* father;
 	void *payload;
-    struct T_UA_list_Element* next;
-    struct T_UA_list_Element* prev;
+    struct UA_list_Element* next;
+    struct UA_list_Element* prev;
 }UA_list_Element;
 
-typedef struct T_UA_list_List {
-   struct T_UA_list_Element* first;
-   struct T_UA_list_Element* last;
+typedef struct UA_list_List {
+   struct UA_list_Element* first;
+   struct UA_list_Element* last;
    UA_Int32 size;
 }UA_list_List;
 

+ 24 - 78
src/Makefile.am

@@ -1,95 +1,42 @@
 #optimization levels depending on debug
 AM_CFLAGS = $(GLOBAL_AM_CFLAGS) -I$(top_builddir)/include -I$(top_builddir)/src -I. -I$(top_builddir)/src/util
-
-
 TOOL_DIR = ../tools
-#__top_builddir__bin_stackTest_out_SOURCES =	opcuaServer.c\
-#											opcua_builtInDatatypes.c\
-#											opcua_binaryEncDec.c\
-#											ua_transportLayer.c\
-#											opcua_builtInDatatypes.h\
-#											opcua_binaryEncDec.h\
-#											ua_transportLayer.h\
-#											opcua_advancedDatatypes.h\
-#											opcua_types.h\
-#											opcua_connectionHelper.h\
-#											tcp_layer.h
-
-#lib_LTLIBRARIES = libstack.la
-#libstack_la_SOURCES = ua_transportLayer.c\
-#					  ua_transportLayer.h\
-#					  opcua_advancedDatatypes.h\
-#					  opcua_connectionHelper.h	
 lib_LTLIBRARIES = libopen62541.la
 libopen62541_la_LDFLAGS = -avoid-version -no-undefined
-#libopen62541_la_SOURCES = 			opcua.c\
-#						ua_basictypes.c\
-#						ua_namespace_0.c\
-#						ua_transportLayer.c\
-#						ua_secureLayer.c\
-#						tcp_layer.c\
-#						ua_transportLayer.h\
-#						opcua_connectionHelper.h\
-#						opcua_encodingLayer.h\
-#						ua_secureLayer.h\
-#						tcp_layer.h\
-#						util/ua_list.c\
-#						util/ua_indexedList.c\
-#						ua_stackInternalTypes.c\
-#						ua_namespace.h\
-#						ua_namespace.c
-
-#libopen62541_ladir = $(top_builddir)/include . $(top_builddir)/src . $(top_builddir)/src/util					
-
-#libopen62541_la_HEADERS = opcua.h\
-#						ua_basictypes.h\
-#						ua_namespace.h\
-#						ua_transportLayer.h\
-#						opcua_connectionHelper.h\
-#						opcua_encodingLayer.h\
-#						ua_secureLayer.h\
-#						ua_namespace.h\
-#						ua_connection.h\
-#						ua_stackInternalTypes.h\
-#						ua_list.h\
-#						ua_indexedList.h
-
-libopen62541_la_SOURCES = opcua.c\
-						ua_basictypes.c\
-						ua_namespace_0.c\
-						util/ua_list.c\
-						util/ua_indexedList.c\
-						ua_transport.c\
-						ua_transport_binary.c\
-						ua_transport_binary_secure.c\
-						ua_namespace.c\
-						ua_services_attribute.c\
-						ua_services_session.c\
-						ua_services_discovery.c\
-						ua_services_securechannel.c\
-						ua_services_view.c\
-						ua_application.c\
-						ua_stack_channel.c\
-						ua_stack_channel_manager.c\
-						ua_transport_connection_manager.c\
-						ua_transport_connection.c
-
-#bin_PROGRAMS= $(top_builddir)/bin/open62541.out
-#__top_builddir__bin_libOpen62541_out_SOURCES = opcuaServer.c
-#libOpen62541_la_LIBADD = ../lib/libOpen62541.la		  										
+libopen62541_la_SOURCES = opcua.c \
+			ua_basictypes.c \
+			ua_namespace_0.c \
+			util/ua_list.c \
+			util/ua_indexedList.c \
+			ua_transport.c \
+			ua_transport_binary.c \
+			ua_transport_binary_secure.c \
+			ua_namespace.c \
+			ua_services_attribute.c \
+			ua_services_session.c \
+			ua_services_discovery.c \
+			ua_services_securechannel.c \
+			ua_services_nodemanagement.c \
+			ua_services_view.c \
+			ua_application.c \
+			ua_xml.c\
+			ua_stack_channel.c \
+			ua_stack_channel_manager.c \
+			ua_transport_connection_manager.c \
+			ua_transport_connection.c
 
 .PHONY: convenience-link clean-convenience-link
 
 convenience-link: $(lib_LTLIBRARIES)
 	@test -e $(top_builddir)/lib || mkdir $(top_builddir)/lib
-	@for soname in `echo | $(EGREP) "^dlname=" $^ | $(SED) -e "s|^dlname='\(.*\)'|\1|"`; do  \
+	@for soname in `echo | $(EGREP) "^dlname=" $^ | $(SED) -e "s|^dlname='\(.*\)'|\1|"`; do \
 		echo "$$soname: creating convenience link from $(abs_builddir)/.libs to $(top_builddir)/lib"; \
 		rm -f $(top_builddir)/lib/$$soname ; \
 		test -e $(abs_builddir)/.libs/$$soname && \
 		cd $(top_builddir)/lib && \
 		$(LN_S) $(abs_builddir)/.libs/$$soname $$soname || true;\
-	done
-	@for aname in `echo | $(EGREP) "^dlname=" $^ | $(SED) -e "s|^dlname='\(.*\)\.\(.*\)'|\1\.a|"`; do  \
+		done
+	@for aname in `echo | $(EGREP) "^dlname=" $^ | $(SED) -e "s|^dlname='\(.*\)\.\(.*\)'|\1\.a|"`; do \
 		echo "$$aname: creating convenience link from $(abs_builddir)/.libs to $(top_builddir)/lib"; \
 		rm -f $(top_builddir)/lib/$$aname ; \
 		test -e $(abs_builddir)/.libs/$$aname && \
@@ -103,4 +50,3 @@ clean-convenience-link:
 all-local: convenience-link
 
 clean-local: clean-convenience-link
-

+ 3 - 6
src/ua_application.c

@@ -27,15 +27,12 @@ UA_Node* create_node_ns0(UA_Int32 class, UA_Int32 nodeClass, UA_Int32 const id,
 #define C2UA_STRING(s) (UA_String) { sizeof(s)-1, (UA_Byte*) s }
 void appMockup_init() {
 	// create namespaces
+	// TODO: A table that maps the namespaceUris to Ids
 	Namespace* ns0;
-	Namespace_create(&ns0,100);
-	ns0->namespaceId = 0;
-	ns0->namespaceUri = C2UA_STRING("http://opcfoundation.org/UA/");
+	Namespace_new(&ns0, 100, 0); //C2UA_STRING("http://opcfoundation.org/UA/"));
 
 	Namespace* local;
-	Namespace_create(&local,100);
-	local->namespaceId = 1;
-	local->namespaceUri = C2UA_STRING("http://localhost:16664/open62541/");
+	Namespace_new(&local, 100, 1); //C2UA_STRING("http://localhost:16664/open62541/"));
 
 	// add to list of namespaces
 	UA_indexedList_init(appMockup.namespaces);

+ 1 - 1
src/ua_application.h

@@ -5,7 +5,7 @@
 #include "ua_namespace.h"
 #include "ua_indexedList.h"
 
-typedef struct Application_T {
+typedef struct Application {
 	UA_ApplicationDescription *description;
 	UA_indexedList_List *namespaces; // each entry is a namespace
 } Application;

Plik diff jest za duży
+ 266 - 250
src/ua_basictypes.c


+ 113 - 158
src/ua_namespace.c

@@ -6,15 +6,24 @@
 /* Internal (not exported) functionality */
 /*****************************************/
 
-UA_Int32 Namespace_TransactionContext_init(Namespace_TransactionContext * tc) {
-	return UA_list_init((UA_list_List *) tc);
-}
+struct Namespace_Entry {
+	UA_UInt64 status;	/* 2 bits status | 14 bits checkout count | 48 bits timestamp */
+	const UA_Node *node;	/* Nodes are immutable. It is not recommended to change nodes in place */
+};
+
+struct Namespace_Entry_Lock {
+	Namespace_Entry *entry;
+};
+
+/* The tombstone (entry.node == 0x01) indicates that an entry was deleted at the position in the
+   hash-map. This is information is used to decide whether the entire table shall be rehashed so
+   that entries are found faster. */
+#define ENTRY_EMPTY UA_NULL
+#define ENTRY_TOMBSTONE 0x01
 
 /* The central data structure is a hash-map of UA_Node objects. Entry lookup via Algorithm D from
    Knuth's TAOCP (no linked lists here). Table of primes and mod-functions are from libiberty
-   (licensed under LGPL) */
-
-typedef UA_UInt32 hash_t;
+   (licensed under LGPL) */ typedef UA_UInt32 hash_t;
 struct prime_ent {
 	hash_t prime;
 	hash_t inv;
@@ -183,105 +192,81 @@ static inline hash_t mod_m2(hash_t h, const Namespace * ns) {
 	return 1 + mod_1(h, p->prime - 2, p->inv_m2, p->shift);
 }
 
-static inline void clear_slot(Namespace * ns, Namespace_Entry * slot) {
-	if(slot->node == UA_NULL)
+static inline void clear_entry(Namespace * ns, Namespace_Entry * entry) {
+	if(entry->node == UA_NULL)
 		return;
 
-#ifdef MULTITHREADING
-	pthread_rwlock_wrlock((pthread_rwlock_t *) slot->lock);	/* Get write lock. */
-#endif
-
-	switch (slot->node->nodeClass) {
+	switch (entry->node->nodeClass) {
 	case UA_NODECLASS_OBJECT:
-		UA_ObjectNode_delete((UA_ObjectNode *) slot->node);
+		UA_ObjectNode_delete((UA_ObjectNode *) entry->node);
 		break;
 	case UA_NODECLASS_VARIABLE:
-		UA_VariableNode_delete((UA_VariableNode *) slot->node);
+		UA_VariableNode_delete((UA_VariableNode *) entry->node);
 		break;
 	case UA_NODECLASS_METHOD:
-		UA_MethodNode_delete((UA_MethodNode *) slot->node);
+		UA_MethodNode_delete((UA_MethodNode *) entry->node);
 		break;
 	case UA_NODECLASS_OBJECTTYPE:
-		UA_ObjectTypeNode_delete((UA_ObjectTypeNode *) slot->node);
+		UA_ObjectTypeNode_delete((UA_ObjectTypeNode *) entry->node);
 		break;
 	case UA_NODECLASS_VARIABLETYPE:
-		UA_VariableTypeNode_delete((UA_VariableTypeNode *) slot->node);
+		UA_VariableTypeNode_delete((UA_VariableTypeNode *) entry->node);
 		break;
 	case UA_NODECLASS_REFERENCETYPE:
-		UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *) slot->node);
+		UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *) entry->node);
 		break;
 	case UA_NODECLASS_DATATYPE:
-		UA_DataTypeNode_delete((UA_DataTypeNode *) slot->node);
+		UA_DataTypeNode_delete((UA_DataTypeNode *) entry->node);
 		break;
 	case UA_NODECLASS_VIEW:
-		UA_ViewNode_delete((UA_ViewNode *) slot->node);
+		UA_ViewNode_delete((UA_ViewNode *) entry->node);
 		break;
 	default:
 		break;
 	}
-	slot->node = UA_NULL;
-
-#ifdef MULTITHREADING
-	pthread_rwlock_destroy((pthread_rwlock_t *) slot->lock);
-	UA_free(slot->lock);
-#endif
-
+	entry->node = UA_NULL;
+	ns->count--;
 }
 
-static inline UA_Int32 find_slot(const Namespace * ns, Namespace_Entry ** slot, const UA_NodeId * nodeid) {
+/* Returns UA_SUCCESS if an entry was found. Otherwise, UA_ERROR is returned and the "entry"
+   argument points to the first free entry under the NodeId. */
+static inline UA_Int32 find_entry(const Namespace * ns, const UA_NodeId * nodeid, Namespace_Entry ** entry) {
 	hash_t h = hash(nodeid);
-	hash_t index, hash2;
-	UA_UInt32 size;
-	Namespace_Entry *entry;
-
-	size = ns->size;
-	index = mod(h, ns);
+	hash_t index = mod(h, ns);
+	UA_UInt32 size = ns->size;
+	Namespace_Entry *e = &ns->entries[index];
 
-	entry = &ns->entries[index];
-	if(entry == UA_NULL)
+	if(e->node == UA_NULL) {
+		*entry = e;
 		return UA_ERROR;
-	if(UA_NodeId_compare(&entry->node->nodeId, nodeid) == UA_EQUAL) {
-		*slot = entry;
+	}
+
+	if(UA_NodeId_compare(&e->node->nodeId, nodeid) == UA_EQUAL) {
+		*entry = e;
 		return UA_SUCCESS;
 	}
 
-	hash2 = mod_m2(h, ns);
+	hash_t hash2 = mod_m2(h, ns);
 	for(;;) {
 		index += hash2;
 		if(index >= size)
 			index -= size;
 
-		entry = &ns->entries[index];
-		if(entry == UA_NULL)
+		e = &ns->entries[index];
+
+		if(e->node == UA_NULL) {
+			*entry = e;
 			return UA_ERROR;
-		if(UA_NodeId_compare(&entry->node->nodeId, nodeid) == UA_EQUAL) {
-			*slot = entry;
+		}
+
+		if(UA_NodeId_compare(&e->node->nodeId, nodeid) == UA_EQUAL) {
+			*entry = e;
 			return UA_SUCCESS;
 		}
 	}
-	return UA_SUCCESS;
-}
-
-/* Always returns an empty slot. This is inevitable if the entries are not completely full. */
-static Namespace_Entry *find_empty_slot(const Namespace * ns, hash_t h) {
-	hash_t index = mod(h, ns);
-	UA_UInt32 size = ns->size;
-	Namespace_Entry *slot = &ns->entries[index];
-
-	if(slot->node == UA_NULL)
-		return slot;
 
-	hash_t hash2 = mod_m2(h, ns);
-	for(;;) {
-		index += hash2;
-		if(index >= size)
-			index -= size;
-
-		slot = &ns->entries[index];
-		if(slot->node == UA_NULL)
-			return slot;
-	}
-	return UA_NULL;
+	/* NOTREACHED */
+	return UA_SUCCESS;
 }
 
 /* The following function changes size of memory allocated for the entries and repeatedly inserts
@@ -309,6 +294,8 @@ static UA_Int32 expand(Namespace * ns) {
 
 	if(UA_alloc((void **)&nentries, sizeof(Namespace_Entry) * nsize) != UA_SUCCESS)
 		return UA_ERR_NO_MEMORY;
+
+	memset(nentries, 0, nsize * sizeof(Namespace_Entry));
 	ns->entries = nentries;
 	ns->size = nsize;
 	ns->sizePrimeIndex = nindex;
@@ -316,8 +303,9 @@ static UA_Int32 expand(Namespace * ns) {
 	Namespace_Entry *p = oentries;
 	do {
 		if(p->node != UA_NULL) {
-			Namespace_Entry *q = find_empty_slot(ns, hash(&p->node->nodeId));
-			*q = *p;
+			Namespace_Entry *e;
+			find_entry(ns, &p->node->nodeId, &e);	/* We know this returns an empty entry here */
+			*e = *p;
 		}
 		p++;
 	} while(p < olimit);
@@ -330,29 +318,22 @@ static UA_Int32 expand(Namespace * ns) {
 /* Exported functions */
 /**********************/
 
-UA_Int32 Namespace_create(Namespace ** result, UA_UInt32 size) {
-	Namespace *ns = UA_NULL;
-	UA_UInt32 sizePrimeIndex = higher_prime_index(size);
-	size = prime_tab[sizePrimeIndex].prime;
-
+UA_Int32 Namespace_new(Namespace ** result, UA_UInt32 size, UA_UInt32 namespaceId) {
+	Namespace *ns;
 	if(UA_alloc((void **)&ns, sizeof(Namespace)) != UA_SUCCESS)
 		return UA_ERR_NO_MEMORY;
 
+	UA_UInt32 sizePrimeIndex = higher_prime_index(size);
+	size = prime_tab[sizePrimeIndex].prime;
 	if(UA_alloc((void **)&ns->entries, sizeof(Namespace_Entry) * size) != UA_SUCCESS) {
 		UA_free(ns);
 		return UA_ERR_NO_MEMORY;
 	}
 
-	/**
-	   set entries to zero:
-	   ns->entries[i].lock = UA_NUll;
-	   ns->entries[i].node = UA_NULL;
-	*/
+	/* set entries to zero */
 	memset(ns->entries, 0, size * sizeof(Namespace_Entry));
 
-	ns->size = size;
-	ns->count = 0;
-	ns->sizePrimeIndex = sizePrimeIndex;
+	*ns = (Namespace) {namespaceId, ns->entries, size, 0, sizePrimeIndex};
 	*result = ns;
 	return UA_SUCCESS;
 }
@@ -361,7 +342,7 @@ static void Namespace_clear(Namespace * ns) {
 	UA_UInt32 size = ns->size;
 	Namespace_Entry *entries = ns->entries;
 	for(UA_UInt32 i = 0; i < size; i++)
-		clear_slot(ns, &entries[i]);
+		clear_entry(ns, &entries[i]);
 	ns->count = 0;
 }
 
@@ -386,118 +367,92 @@ void Namespace_delete(Namespace * ns) {
 	UA_free(ns);
 }
 
-UA_Int32 Namespace_insert(Namespace * ns, UA_Node * node) {
+UA_Int32 Namespace_insert(Namespace * ns, const UA_Node * node) {
 	if(ns->size * 3 <= ns->count * 4) {
 		if(expand(ns) != UA_SUCCESS)
 			return UA_ERROR;
 	}
 
-	hash_t h = hash(&node->nodeId);
-	Namespace_Entry *slot = find_empty_slot(ns, h);
+	Namespace_Entry *entry;
+	UA_Int32 found = find_entry(ns, &node->nodeId, &entry);
 
-#ifdef MULTITHREADING
-	if(UA_alloc((void **)&slot->lock, sizeof(pthread_rwlock_t)) != UA_SUCCESS)
-		return UA_ERR_NO_MEMORY;
-	pthread_rwlock_init((pthread_rwlock_t *) slot->lock, NULL);
-#endif
+	if(found == UA_SUCCESS)
+		return UA_ERROR;	/* There is already an entry for that nodeid */
 
-	slot->node = node;
+	entry->node = node;
 	ns->count++;
 	return UA_SUCCESS;
 }
 
-UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result, Namespace_Lock ** lock) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return UA_ERROR;
-
-#ifdef MULTITHREADING
-	if(pthread_rwlock_rdlock((pthread_rwlock_t *) slot->lock) != 0)
-		return UA_ERROR;
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
-	return UA_SUCCESS;
-}
+UA_Int32 Namespace_insertUnique(Namespace * ns, UA_Node * node) {
+	if(ns->size * 3 <= ns->count * 4) {
+		if(expand(ns) != UA_SUCCESS)
+			return UA_ERROR;
+	}
+	// find unoccupied numeric nodeid
+	node->nodeId.namespace = ns->namespaceId;
+	node->nodeId.encodingByte = UA_NODEIDTYPE_NUMERIC;
+	node->nodeId.identifier.numeric = ns->count;
 
-UA_Int32 Namespace_getWritable(const Namespace * ns, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return UA_ERROR;
+	hash_t h = hash(&node->nodeId);
+	hash_t hash2 = mod_m2(h, ns);
+	UA_UInt32 size = ns->size;
 
-#ifdef MULTITHREADING
-	if(pthread_rwlock_wrlock((pthread_rwlock_t *) slot->lock) != 0)
-		return UA_ERROR;
-	*lock = slot->lock;
-#endif
+	// advance integer (hash) until a free entry is found
+	Namespace_Entry *entry = UA_NULL;
+	while(1) {
+		if(find_entry(ns, &node->nodeId, &entry) != UA_SUCCESS)
+			break;
+		node->nodeId.identifier.numeric += hash2;
+		if(node->nodeId.identifier.numeric >= size)
+			node->nodeId.identifier.numeric -= size;
+	}
 
-	*result = slot->node;
+	entry->node = node;
+	ns->count++;
 	return UA_SUCCESS;
 }
 
-#ifdef MULTITHREADING
-static inline void release_context_walker(void *lock) {
-	pthread_rwlock_unlock(lock);
+UA_Int32 Namespace_contains(const Namespace * ns, const UA_NodeId * nodeid) {
+	Namespace_Entry *entry;
+	return find_entry(ns, nodeid, &entry);
 }
-#endif
 
-UA_Int32 Namespace_transactionGet(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** const result, Namespace_Lock ** lock) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
+UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, const UA_Node **result,
+					   Namespace_Entry_Lock ** lock) {
+	Namespace_Entry *entry;
+	if(find_entry(ns, nodeid, &entry) != UA_SUCCESS)
 		return UA_ERROR;
 
-#ifdef MULTITHREADING
-	if(pthread_rwlock_tryrdlock((pthread_rwlock_t *) slot->lock) != 0) {
-		/* Transaction failed. Release all acquired locks and bail out. */
-		UA_list_destroy((UA_list_List *) tc, release_context_walker);
-		return UA_ERROR;
-	}
-	UA_list_addPayloadToBack((UA_list_List *) tc, slot->lock);
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
+	*result = entry->node;
 	return UA_SUCCESS;
 }
 
-UA_Int32 Namespace_transactionGetWritable(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
+UA_Int32 Namespace_remove(Namespace * ns, const UA_NodeId * nodeid) {
+	Namespace_Entry *entry;
+	if(find_entry(ns, nodeid, &entry) != UA_SUCCESS)
 		return UA_ERROR;
 
-#ifdef MULTITHREADING
-	if(pthread_rwlock_trywrlock((pthread_rwlock_t *) slot->lock) != 0) {
-		/* Transaction failed. Release all acquired locks and bail out. */
-		UA_list_destroy((UA_list_List *) tc, release_context_walker);
-		return UA_ERROR;
-	}
-	UA_list_addPayloadToBack((UA_list_List *) tc, slot->lock);
-	*lock = slot->lock;
-#endif
-
-	*result = slot->node;
-	return UA_SUCCESS;
-}
-
-void Namespace_remove(Namespace * ns, UA_NodeId * nodeid) {
-	Namespace_Entry *slot;
-	if(find_slot(ns, &slot, nodeid) != UA_SUCCESS)
-		return;
 	// TODO: Check if deleting the node makes the Namespace inconsistent.
-	clear_slot(ns, slot);
+	clear_entry(ns, entry);
 
 	/* Downsize the hashmap if it is very empty */
 	if(ns->count * 8 < ns->size && ns->size > 32)
 		expand(ns);
+
+	return UA_SUCCESS;
 }
 
 UA_Int32 Namespace_iterate(const Namespace * ns, Namespace_nodeVisitor visitor) {
-	UA_UInt32 i;
-	for(i = 0; i < ns->size; i++) {
+	if(visitor == UA_NULL) return UA_SUCCESS;
+	for(UA_UInt32 i = 0; i < ns->size; i++) {
 		Namespace_Entry *entry = &ns->entries[i];
-		if(entry != UA_NULL && visitor != UA_NULL)
+		if(entry->node != UA_NULL)
 			visitor(entry->node);
 	}
 	return UA_SUCCESS;
 }
+
+void Namespace_Entry_Lock_release(Namespace_Entry_Lock * lock) {
+	;
+}

+ 33 - 51
src/ua_namespace.h

@@ -9,47 +9,31 @@
 #define _XOPEN_SOURCE 500
 #define __USE_UNIX98
 #include <pthread.h>
-typedef struct pthread_rwlock_t Namespace_Lock;
-#else
-typedef void Namespace_Lock;
 #endif
 
-static inline void Namespace_Lock_release(Namespace_Lock * lock) {
-#ifdef MULTITHREADING
-	pthread_rwlock_unlock((pthread_rwlock_t *) lock);
-#endif
-}
-
-/* Poor-man's transactions: If we need multiple locks and at least one of them is a writelock
-   ("transaction"), a deadlock can be introduced in conjunction with a second thread.
-
-   Convention: All nodes in a transaction (read and write) must be locked before the first write.
-   If one write-lock cannot be acquired immediately, bail out and restart the transaction. A
-   Namespace_TransactionContext is currently only a linked list of the acquired locks. More advanced
-   transaction mechanisms will be established once the runtime behavior can be observed. */
-typedef UA_list_List Namespace_TransactionContext;
-UA_Int32 Namespace_TransactionContext_init(Namespace_TransactionContext * tc);
+/** @brief Namespace entries point to an UA_Node. But the actual data structure
+	is opaque outside of ua_namespace.c */
+struct Namespace_Entry;
+typedef struct Namespace_Entry Namespace_Entry;
 
-/* Each namespace is a hash-map of NodeIds to Nodes. Every entry in the hashmap consists of a
-   pointer to a read-write lock and a pointer to the Node. */
-typedef struct Namespace_Entry_T {
-#ifdef MULTITHREADING
-	Namespace_Lock *lock;	/* locks are heap-allocated */
-#endif
-	UA_Node *node;
-} Namespace_Entry;
-
-typedef struct Namespace_T {
-	UA_Int32 namespaceId;
-	UA_String namespaceUri;
+/** @brief Namespace datastructure. It mainly serves as a hashmap to UA_Nodes. */
+typedef struct Namespace {
+	UA_UInt32 namespaceId;
 	Namespace_Entry *entries;
 	UA_UInt32 size;
 	UA_UInt32 count;
 	UA_UInt32 sizePrimeIndex;	/* Current size, as an index into the table of primes.  */
 } Namespace;
 
+/** Namespace locks indicate that a thread currently operates on an entry. */
+struct Namespace_Entry_Lock;
+typedef struct Namespace_Entry_Lock Namespace_Entry_Lock;
+
+/** @brief Release a lock on a namespace entry. */
+void Namespace_Entry_Lock_release(Namespace_Entry_Lock * lock);
+
 /** @brief Create a new namespace */
-UA_Int32 Namespace_create(Namespace ** result, UA_UInt32 size);
+UA_Int32 Namespace_new(Namespace ** result, UA_UInt32 size, UA_UInt32 namespaceId);
 
 /** @brief Delete all nodes in the namespace */
 void Namespace_empty(Namespace * ns);
@@ -57,33 +41,31 @@ void Namespace_empty(Namespace * ns);
 /** @brief Delete the namespace and all nodes in it */
 void Namespace_delete(Namespace * ns);
 
-/** @brief Insert a new node into the namespace */
-UA_Int32 Namespace_insert(Namespace * ns, UA_Node * node);
+/** @brief Insert a new node into the namespace. Abort an entry with the same
+	NodeId is already present */
+UA_Int32 Namespace_insert(Namespace * ns, const UA_Node * node);
+
+/** @brief Insert a new node or replace an existing node if an entry has the same NodeId. */
+UA_Int32 Namespace_insertOrReplace(Namespace * ns, const UA_Node * node);
+
+/** @brief Find an unused (numeric) NodeId in the namespace and insert the node.
+	The node is modified to contain the new nodeid after insertion. */
+UA_Int32 Namespace_insertUnique(Namespace * ns, UA_Node * node);
 
 /** @brief Remove a node from the namespace */
-void Namespace_remove(Namespace * ns, UA_NodeId * nodeid);
+UA_Int32 Namespace_remove(Namespace * ns, const UA_NodeId * nodeid);
+
+/** @brief Tests whether the namespace contains an entry for a given NodeId */
+UA_Int32 Namespace_contains(const Namespace * ns, const UA_NodeId * nodeid);
 
 /** @brief Retrieve a node (read-only) from the namespace. Nodes are identified
 	by their NodeId. After the Node is no longer used, the lock needs to be
 	released. */
-UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, UA_Node const **result, Namespace_Lock ** lock);
-
-/** @brief Retrieve a node (read and write) from the namespace. Nodes are
-	identified by their NodeId. After the Node is no longer used, the lock needs
-	to be released. */
-UA_Int32 Namespace_getWritable(Namespace const *ns, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock);
-
-/** @brief Retrieve a node (read-only) as part of a transaction. If multiples
-	nodes are to be retrieved as part of a transaction, the transaction context
-	needs to be specified. */
-UA_Int32 Namespace_transactionGet(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** const result, Namespace_Lock ** lock);
-
-/** @brief Retrieve a node (read and write) as part of a transaction. If
-	multiples nodes are to be retrieved as part of a transaction, the
-	transaction context needs to be specified. */
-UA_Int32 Namespace_transactionGetWritable(Namespace * ns, Namespace_TransactionContext * tc, const UA_NodeId * nodeid, UA_Node ** result, Namespace_Lock ** lock);
+UA_Int32 Namespace_get(const Namespace *ns, const UA_NodeId * nodeid, const UA_Node **result,
+					   Namespace_Entry_Lock ** lock);
 
-typedef void (*Namespace_nodeVisitor) (UA_Node const *node);
+/** @brief A function that can be evaluated on all entries in a namespace via Namespace_iterate */
+typedef void (*Namespace_nodeVisitor) (const UA_Node *node);
 
 /** @brief Iterate over all nodes in a namespace */
 UA_Int32 Namespace_iterate(const Namespace * ns, Namespace_nodeVisitor visitor);

+ 29 - 3
src/ua_services.h

@@ -1,3 +1,9 @@
+/**
+ * @file ua_services.h
+ *
+ * @brief Defines the method signatures for all the standard defined services.
+ */
+
 #ifndef UA_SERVICES_H_
 #define UA_SERVICES_H_
 
@@ -5,6 +11,14 @@
 #include "ua_application.h"
 #include "ua_transport_binary_secure.h"
 
+/**
+ * @defgroup services Services
+ *
+ * @brief This module describes all the services used to communicate in in OPC UA.
+ *
+ * @{
+ */
+
 /**
  * @name Discovery Service Set
  *
@@ -90,7 +104,11 @@ UA_Int32 Service_CloseSession(const UA_CloseSessionRequest *request, UA_CloseSes
  *
  * @{
  */
-// Service_AddNodes
+
+/**
+ * @brief This Service is used to add one or more Nodes into the AddressSpace hierarchy.
+ */
+UA_Int32 Service_AddNodes( const UA_AddNodesRequest *request, UA_AddNodesResponse *response);
 // Service_AddReferences
 // Service_DeleteNodes
 // Service_DeleteReferences
@@ -110,13 +128,19 @@ UA_Int32 Service_CloseSession(const UA_CloseSessionRequest *request, UA_CloseSes
  * The browse can be further limited by the use of a View. This Browse Service
  * also supports a primitive filtering capability.
  */ 
-UA_Int32 Service_Browse(const UA_BrowseRequest *request, UA_BrowseResponse *response);
+UA_Int32 Service_Browse( const UA_BrowseRequest *request, UA_BrowseResponse *response);
+
+/**
+ * @brief This Service is used to translate textual node paths to their respective ids.
+ */
+UA_Int32 Service_TranslateBrowsePathsToNodeIds( const UA_TranslateBrowsePathsToNodeIdsRequest *request, UA_TranslateBrowsePathsToNodeIdsResponse *response);
 // Service_BrowseNext
-// Service_TranslateBrowsePathsRoNodeIds
+// Service_TranslateBrowsePathsToNodeIds
 // Service_RegisterNodes
 // Service_UnregisterNodes
 /** @} */
 
+
 /* Part 4: 5.9 Query Service Set */
 /**
  * @name Query Service Set
@@ -209,4 +233,6 @@ UA_Int32 Service_CreateMonitoredItems(const UA_CreateMonitoredItemsRequest *requ
 // Service_DeleteSubscription
 /** @} */
 
+/** @} */ // end of group
+
 #endif

+ 103 - 86
src/ua_services_attribute.c

@@ -26,168 +26,185 @@ enum UA_AttributeId {
 	UA_ATTRIBUTEID_USEREXECUTABLE = 22
 };
 
-static UA_DataValue * service_read_node(Application *app, const UA_ReadValueId *id) {
-	UA_DataValue *v; UA_DataValue_new(&v);
-	
-	DBG(printf("service_read_node - entered with ns=%d,id=%d,attr=%i\n",id->nodeId.namespace, id->nodeId.identifier.numeric, id->attributeId));
+#define CHECK_NODECLASS(CLASS) do {									\
+		if((node->nodeClass & (CLASS)) != 0x00) {					\
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;		\
+			v->status = UA_STATUSCODE_BADNOTREADABLE;				\
+		}															\
+		break;														\
+	} while(0)
+
+static UA_DataValue *service_read_node(Application * app, const UA_ReadValueId * id) {
+	UA_DataValue *v;
+	UA_DataValue_new(&v);
+
+	DBG(printf("service_read_node - entered with ns=%d,id=%d,attr=%i\n", id->nodeId.namespace, id->nodeId.identifier.numeric, id->attributeId));
 	Namespace *ns = UA_indexedList_findValue(app->namespaces, id->nodeId.namespace);
 
-	if (ns == UA_NULL) {
-		DBG_VERBOSE(printf("service_read_node - unknown namespace %d\n",id->nodeId.namespace));
+	if(ns == UA_NULL) {
+		DBG_VERBOSE(printf("service_read_node - unknown namespace %d\n", id->nodeId.namespace));
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		return v;
 	}
-	DBG_VERBOSE(UA_String_printf(",namespaceUri=",&(ns->namespaceUri)));
-	
+	DBG_VERBOSE(UA_String_printf(",namespaceUri=", &(ns->namespaceUri)));
+
 	UA_Node const *node = UA_NULL;
-	Namespace_Lock *lock = UA_NULL;
-	DBG_VERBOSE(UA_NodeId_printf("service_read_node - search for ",&(id->nodeId)));
+	Namespace_Entry_Lock *lock = UA_NULL;
+
+	DBG_VERBOSE(UA_NodeId_printf("service_read_node - search for ", &(id->nodeId)));
 	UA_Int32 result = Namespace_get(ns, &(id->nodeId), &node, &lock);
 	if(result != UA_SUCCESS || node == UA_NULL) {
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
 		return v;
 	}
-	DBG_VERBOSE(UA_NodeId_printf("service_read_node - found node=",&(node->nodeId)));
+	DBG_VERBOSE(UA_NodeId_printf("service_read_node - found node=", &(node->nodeId)));
 
-	switch(id->attributeId) {
+	UA_Int32 retval = UA_SUCCESS;
+
+	switch (id->attributeId) {
 	case UA_ATTRIBUTEID_NODEID:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_NODEID, &node->nodeId);
 		break;
 	case UA_ATTRIBUTEID_NODECLASS:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_UINT32, &node->nodeClass);
 		break;
 	case UA_ATTRIBUTEID_BROWSENAME:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_QUALIFIEDNAME, &node->browseName);
 		break;
 	case UA_ATTRIBUTEID_DISPLAYNAME:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_LOCALIZEDTEXT, &node->displayName);
 		break;
 	case UA_ATTRIBUTEID_DESCRIPTION:
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADNOTREADABLE;
 		break;
 	case UA_ATTRIBUTEID_WRITEMASK:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_UINT32, &node->writeMask);
 		break;
 	case UA_ATTRIBUTEID_USERWRITEMASK:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_UINT32, &node->userWriteMask);
 		break;
 	case UA_ATTRIBUTEID_ISABSTRACT:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_ReferenceTypeNode *) node)->isAbstract);
 		break;
 	case UA_ATTRIBUTEID_SYMMETRIC:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_ReferenceTypeNode *) node)->symmetric);
 		break;
 	case UA_ATTRIBUTEID_INVERSENAME:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_LOCALIZEDTEXT, &((UA_ReferenceTypeNode *) node)->inverseName);
 		break;
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VIEW);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_ViewNode *) node)->containsNoLoops);
 		break;
 	case UA_ATTRIBUTEID_EVENTNOTIFIER:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VIEW);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BYTE, &((UA_ViewNode *) node)->eventNotifier);
 		break;
 	case UA_ATTRIBUTEID_VALUE:
-		if (node->nodeClass != UA_NODECLASS_VARIABLE) {
-			v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-			v->status = UA_STATUSCODE_BADNOTREADABLE;
-			break;
-		}
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE | UA_DATAVALUE_ENCODINGMASK_VARIANT;
-		v->status = UA_STATUSCODE_GOOD;
-
-		// be careful not to release the node before encoding the message
-
-		UA_VariableNode * vn = (UA_VariableNode*) node;
-		// FIXME: delete will be called later on on on all the members of v, so essentially
-		// the item's data will be removed from the namespace-object. We would need
-		// something like a deep copy function just as we have it for the strings
-		// UA_Variant_copy(UA_Variant* src, UA_Variant* dst);
-
-		// FIXME: mockup code - we know that for 2255 we simply need to copy the array
-		if (node->nodeId.identifier.numeric == 2255) {
-			v->value = vn->value;
-			UA_Array_copy((void const*const*)vn->value.data,vn->value.arrayLength,UA_ns0ToVTableIndex(vn->value.vt->ns0Id),(void***)&v->value.data);
-		} else {
-			v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-			v->status = UA_STATUSCODE_BADNOTREADABLE;
-		}
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		// TODO: Ensure that the borrowed value is not freed prematurely (multithreading)
+		retval |= UA_Variant_borrowSetValue(&v->value, UA_VARIANT, &((UA_VariableNode *) node)->value);
 		break;
 	case UA_ATTRIBUTEID_DATATYPE:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_NODEID, &((UA_VariableTypeNode *) node)->dataType);
 		break;
 	case UA_ATTRIBUTEID_VALUERANK:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_INT32, &((UA_VariableTypeNode *) node)->valueRank);
 		break;
 	case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		UA_Variant_copySetArray(&v->value, UA_UINT32, ((UA_VariableTypeNode *) node)->arrayDimensionsSize, sizeof(UA_UInt32),
+								&((UA_VariableTypeNode *) node)->arrayDimensions);
 		break;
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BYTE, &((UA_VariableNode *) node)->accessLevel);
 		break;
 	case UA_ATTRIBUTEID_USERACCESSLEVEL:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BYTE, &((UA_VariableNode *) node)->userAccessLevel);
 		break;
 	case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_DOUBLE, &((UA_VariableNode *) node)->minimumSamplingInterval);
 		break;
 	case UA_ATTRIBUTEID_HISTORIZING:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_VariableNode *) node)->historizing);
 		break;
 	case UA_ATTRIBUTEID_EXECUTABLE:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_METHOD);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_MethodNode *) node)->executable);
 		break;
 	case UA_ATTRIBUTEID_USEREXECUTABLE:
-		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-		v->status = UA_STATUSCODE_BADNOTREADABLE;
+		CHECK_NODECLASS(UA_NODECLASS_METHOD);
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
+		retval |= UA_Variant_copySetValue(&v->value, UA_BOOLEAN, &((UA_MethodNode *) node)->userExecutable);
 		break;
 	default:
 		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
 		v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		break;
 	}
-	Namespace_Lock_release(lock);
-	return v;
-}
 
-UA_Int32 Service_Read(const UA_ReadRequest *request, UA_ReadResponse *response ) {
+	Namespace_Entry_Lock_release(lock);
 
-	//TODO use request->requestHeader.authenticationToken to get the correct session
+	if(retval != UA_SUCCESS) {
+		v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
+		v->status = UA_STATUSCODE_BADNOTREADABLE;
+	}
+
+	return v;
+}
 
-	//if(channel->session == UA_NULL || channel->session->application == UA_NULL) return UA_ERROR; // TODO: Return error message
+UA_Int32 Service_Read(const UA_ReadRequest * request, UA_ReadResponse * response) {
+//TODO GET SESSION HERE//if(channel->session == UA_NULL || channel->session->application == UA_NULL)
+	//	return UA_ERROR;	// TODO: Return error message
 
+	int readsize = request->nodesToReadSize;
+	/* NothingTodo */
+	if(readsize <= 0) {
+		response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+		response->resultsSize = 0;
+		return UA_SUCCESS;
+	}
 
-	UA_Int32 readsize = request->nodesToReadSize > 0 ? request->nodesToReadSize : 0;
 	response->resultsSize = readsize;
 	UA_alloc((void **)&response->results, sizeof(void *)*readsize);
 	for(int i=0;i<readsize;i++) {
 		DBG_VERBOSE(printf("service_read - attributeId=%d\n",request->nodesToRead[i]->attributeId));
 		DBG_VERBOSE(UA_NodeId_printf("service_read - nodeId=",&(request->nodesToRead[i]->nodeId)));
-
-	//TODO provide the part of the adress space which is bound to session
-	//response->results[i] = service_read_node(channel->session->application, request->nodesToRead[i]);
+//TODO GET SESSION HERE//response->results[i] = service_read_node(channel->session->application, request->nodesToRead[i]);
 	}
+	response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
 	response->diagnosticInfosSize = -1;
 	return UA_SUCCESS;
 }

+ 0 - 1
src/ua_services_discovery.c

@@ -1,7 +1,6 @@
 #include "ua_services.h"
 UA_Int32 Service_GetEndpoints(const UA_GetEndpointsRequest* request, UA_GetEndpointsResponse *response) {
 	UA_String_printx("endpointUrl=", &request->endpointUrl);
-
 	response->endpointsSize = 1;
 	UA_Array_new((void***) &response->endpoints,response->endpointsSize,UA_ENDPOINTDESCRIPTION);
 

+ 90 - 0
src/ua_services_nodemanagement.c

@@ -0,0 +1,90 @@
+#include "ua_services.h"
+#include "ua_statuscodes.h"
+#include "ua_namespace.h"
+
+#define CHECKED_ACTION(ACTION, CLEAN_UP, GOTO) do {	\
+	status |= ACTION; \
+	if(status != UA_SUCCESS) { \
+		CLEAN_UP; \
+		goto GOTO; \
+	} } while(0) \
+
+static UA_AddNodesResult * addSingleNode(Application *app, UA_AddNodesItem *item) {
+	UA_AddNodesResult *result;
+	UA_AddNodesResult_new(&result);
+
+	Namespace *parent_ns = UA_indexedList_findValue(app->namespaces, item->parentNodeId.nodeId.namespace);
+	// TODO: search for namespaceUris and not only ns-ids.
+	if(parent_ns == UA_NULL) {
+		result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
+		return result;
+	}
+
+	Namespace *ns = UA_NULL;
+	UA_Boolean nodeid_isnull = UA_NodeId_isNull(&item->requestedNewNodeId.nodeId);
+
+	if(nodeid_isnull) ns = parent_ns;
+	else ns = UA_indexedList_findValue(app->namespaces, item->requestedNewNodeId.nodeId.namespace);
+
+	if(ns == UA_NULL || item->requestedNewNodeId.nodeId.namespace == 0) {
+		result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
+		return result;
+	}
+
+	UA_Int32 status = UA_SUCCESS;
+	const UA_Node *parent;
+	Namespace_Entry_Lock *parent_lock = UA_NULL;
+
+	CHECKED_ACTION(Namespace_get(parent_ns, &item->parentNodeId.nodeId, &parent, &parent_lock),
+				   result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID, ret);
+
+	if(!nodeid_isnull && Namespace_contains(ns, &item->requestedNewNodeId.nodeId)) {
+		result->statusCode = UA_STATUSCODE_BADNODEIDEXISTS;
+		goto ret;
+	}
+
+	/**
+	   TODO:
+
+	   1) Check for the remaining conditions 
+	   Bad_ReferenceTypeIdInvalid  See Table 166 for the description of this result code.
+	   Bad_ReferenceNotAllowed  The reference could not be created because it violates constraints imposed by the data model.
+	   Bad_NodeClassInvalid  See Table 166 for the description of this result code.
+	   Bad_BrowseNameInvalid  See Table 166 for the description of this result code.
+	   Bad_BrowseNameDuplicated  The browse name is not unique among nodes that share the same relationship with the parent.
+	   Bad_NodeAttributesInvalid  The node Attributes are not valid for the node class.
+	   Bad_TypeDefinitionInvalid  See Table 166 for the description of this result code.
+	   Bad_UserAccessDenied  See Table 165 for the description of this result code
+
+	   2) Parse the UA_Node from the ExtensionObject
+	   3) Create a new entry in the namespace
+	   4) Add the reference to the parent.
+	 */
+
+ ret:
+	Namespace_Entry_Lock_release(parent_lock);
+	return result;
+}
+
+UA_Int32 Service_AddNodes(const UA_AddNodesRequest *request, UA_AddNodesResponse *response) {
+//TODO GET SESSION HERE	if(channel->session == UA_NULL || channel->session->application == UA_NULL)
+//		return UA_ERROR;	// TODO: Return error message
+
+	int nodestoaddsize = request->nodesToAddSize;
+	if(nodestoaddsize <= 0) {
+		response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+		response->resultsSize = 0;
+		return UA_SUCCESS;
+	}
+
+	response->resultsSize = nodestoaddsize;
+	UA_alloc((void **)&response->results, sizeof(void *) * nodestoaddsize);
+	for(int i = 0; i < nodestoaddsize; i++) {
+		DBG_VERBOSE(UA_QualifiedName_printf("service_addnodes - name=", &(request->nodesToAdd[i]->browseName)));
+//TODO GET SESSION HERE		response->results[i] = addSingleNode(channel->session->application, request->nodesToAdd[i]);
+	}
+	response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
+	response->diagnosticInfosSize = -1;
+	return UA_SUCCESS;
+	
+}

+ 22 - 0
src/ua_services_view.c

@@ -1,4 +1,5 @@
 #include "ua_services.h"
+#include "ua_statuscodes.h"
 
 UA_Int32 Service_Browse(const UA_BrowseRequest *request, UA_BrowseResponse *response) {
 	UA_Int32 retval = UA_SUCCESS;
@@ -9,3 +10,24 @@ UA_Int32 Service_Browse(const UA_BrowseRequest *request, UA_BrowseResponse *resp
 	}
 	return retval;
 }
+
+UA_Int32 Service_TranslateBrowsePathsToNodeIds(const UA_TranslateBrowsePathsToNodeIdsRequest *request, UA_TranslateBrowsePathsToNodeIdsResponse *response)
+{
+	UA_Int32 retval = UA_SUCCESS;
+
+	DBG_VERBOSE(printf("TranslateBrowsePathsToNodeIdsService - %i path(s)", request->browsePathsSize));
+	//Allocate space for a correct answer
+	UA_Array_new((void***)&(response->results),request->browsePathsSize,UA_BROWSEPATHRESULT);
+
+	response->resultsSize = request->browsePathsSize;
+
+	UA_BrowsePathResult* path;
+	for(UA_Int32 i = 0;i<request->browsePathsSize;i++){
+		UA_BrowsePathResult_new(&path);
+		//FIXME: implement
+		path->statusCode = UA_STATUSCODE_BADQUERYTOOCOMPLEX;
+		(response->results[i]) = path;
+	}
+
+	return retval;
+}

+ 1 - 0
src/ua_stack_channel.c

@@ -33,6 +33,7 @@ typedef struct SL_Channel1 {
 	SL_ChannelIdProvider channelIdProvider;
 }SL_Channel1;
 
+
 UA_Int32 SL_Channel_registerTokenProvider(SL_secureChannel channel, SL_ChannelSecurityTokenProvider provider)
 {
 	((SL_Channel1*)channel)->tokenProvider = provider;

+ 0 - 2
src/ua_stack_channel.h

@@ -24,8 +24,6 @@ typedef struct SL_Channel1 *SL_secureChannel;
 typedef UA_Int32 (*SL_ChannelSecurityTokenProvider)(SL_secureChannel ,UA_Int32 , SecurityTokenRequestType, UA_ChannelSecurityToken*);
 typedef UA_Int32 (*SL_ChannelIdProvider)(UA_UInt32*);
 
-
-
 UA_Int32 SL_Channel_new(SL_secureChannel **channel,
 		SL_ChannelIdProvider channelIdProvider,
 		SL_ChannelSecurityTokenProvider tokenProvider,

+ 1 - 0
src/ua_stack_channel_manager.c

@@ -49,6 +49,7 @@ UA_Int32 SL_ChannelManager_addChannel(SL_secureChannel *channel)
 {
 	if (channelManager->maxChannelCount > channelManager->currentChannelCount)
 	{
+
 //TODO lock access (mulitthreading)------------
 		UA_list_Element *element;
 		UA_alloc((void**)&element, sizeof(UA_list_Element));

+ 10 - 10
src/ua_transport.h

@@ -13,7 +13,7 @@ typedef enum UA_ConnectionState {
 	CONNECTIONSTATE_CLOSE
 }UA_ConnectionState;
 
-typedef struct Session_T {
+typedef struct Session {
 	UA_Int32 sessionId;
 	Application *application;
 } Session;
@@ -48,7 +48,7 @@ void UA_MessageType_printf(char *label, UA_MessageType* p);
 
 /** @name UA_UA_OPCUATcpMessageHeader */
 /** @brief TCP Header */
-typedef struct UA_OPCUATcpMessageHeader_T {
+typedef struct UA_OPCUATcpMessageHeader {
 	UA_MessageType messageType; // MessageType instead of UInt32
 	UA_Byte isFinal;
 	UA_UInt32 messageSize;
@@ -63,7 +63,7 @@ UA_Int32 UA_OPCUATcpMessageHeader_new(UA_OPCUATcpMessageHeader ** p);
 
 /** @name UA_UA_OPCUATcpHelloMessage */
 /** @brief Hello Message */
-typedef struct UA_OPCUATcpHelloMessage_T {
+typedef struct UA_OPCUATcpHelloMessage {
 	UA_UInt32 protocolVersion;
 	UA_UInt32 receiveBufferSize;
 	UA_UInt32 sendBufferSize;
@@ -81,7 +81,7 @@ UA_Int32 UA_OPCUATcpHelloMessage_new(UA_OPCUATcpHelloMessage ** p);
 
 /** @name UA_UA_OPCUATcpAcknowledgeMessage */
 /** @brief Acknowledge Message */
-typedef struct UA_OPCUATcpAcknowledgeMessage_T {
+typedef struct UA_OPCUATcpAcknowledgeMessage {
 	UA_UInt32 protocolVersion;
 	UA_UInt32 receiveBufferSize;
 	UA_UInt32 sendBufferSize;
@@ -98,7 +98,7 @@ UA_Int32 UA_OPCUATcpAcknowledgeMessage_new(UA_OPCUATcpAcknowledgeMessage ** p);
 
 /** @name UA_UA_SecureConversationMessageHeader */
 /** @brief Secure Layer Sequence Header */
-typedef struct UA_SecureConversationMessageHeader_T {
+typedef struct UA_SecureConversationMessageHeader {
 	// UA_OPCUATcpMessageHeader messageHeader; // Treated with custom code
 	UA_UInt32 secureChannelId;
 } UA_SecureConversationMessageHeader;
@@ -112,7 +112,7 @@ UA_Int32 UA_SecureConversationMessageHeader_new(UA_SecureConversationMessageHead
 
 /** @name UA_UA_AsymmetricAlgorithmSecurityHeader */
 /** @brief Security Header> */
-typedef struct UA_AsymmetricAlgorithmSecurityHeader_T {
+typedef struct UA_AsymmetricAlgorithmSecurityHeader {
 	UA_ByteString securityPolicyUri;
 	UA_ByteString senderCertificate;
 	UA_ByteString receiverCertificateThumbprint;
@@ -128,7 +128,7 @@ UA_Int32 UA_AsymmetricAlgorithmSecurityHeader_new(UA_AsymmetricAlgorithmSecurity
 
 /** @name UA_UA_SymmetricAlgorithmSecurityHeader */
 /** @brief Secure Layer Symmetric Algorithm Header */
-typedef struct UA_SymmetricAlgorithmSecurityHeader_T {
+typedef struct UA_SymmetricAlgorithmSecurityHeader {
 	UA_UInt32 tokenId;
 } UA_SymmetricAlgorithmSecurityHeader;
 UA_Int32 UA_SymmetricAlgorithmSecurityHeader_calcSize(UA_SymmetricAlgorithmSecurityHeader const* ptr);
@@ -141,7 +141,7 @@ UA_Int32 UA_SymmetricAlgorithmSecurityHeader_new(UA_SymmetricAlgorithmSecurityHe
 
 /** @name UA_UA_SequenceHeader */
 /** @brief Secure Layer Sequence Header */
-typedef struct UA_SequenceHeader_T {
+typedef struct UA_SequenceHeader {
 	UA_UInt32 sequenceNumber;
 	UA_UInt32 requestId;
 } UA_SequenceHeader;
@@ -155,7 +155,7 @@ UA_Int32 UA_SequenceHeader_new(UA_SequenceHeader ** p);
 
 /** @name UA_UA_SecureConversationMessageFooter */
 /** @brief Secure Conversation Message Footer */
-typedef struct UA_SecureConversationMessageFooter_T {
+typedef struct UA_SecureConversationMessageFooter {
 	UA_Int32 paddingSize;
 	UA_Byte** padding;
 	UA_Byte signature;
@@ -170,7 +170,7 @@ UA_Int32 UA_SecureConversationMessageFooter_new(UA_SecureConversationMessageFoot
 
 /** @name UA_UA_SecureConversationMessageAbortBody */
 /** @brief Secure Conversation Message Abort Body */
-typedef struct UA_SecureConversationMessageAbortBody_T {
+typedef struct UA_SecureConversationMessageAbortBody {
 	UA_UInt32 error;
 	UA_String reason;
 } UA_SecureConversationMessageAbortBody;

+ 27 - 28
src/ua_transport_binary.c

@@ -116,34 +116,34 @@ static UA_Int32 TL_handleHello(TL_Connection* connection, const UA_ByteString* m
 	return retval;
 }
 */
+
+static UA_Int32 TL_securitySettingsMockup_get(UA_ByteString *receiverCertificateThumbprint,UA_ByteString *securityPolicyUri, UA_ByteString *senderCertificate)
+{
+	receiverCertificateThumbprint->data = UA_NULL;
+	receiverCertificateThumbprint->length = 0;
+
+	UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None",(UA_String*)securityPolicyUri);
+
+	senderCertificate->data = UA_NULL;
+	senderCertificate->length = 0;
+
+	return UA_SUCCESS;
+}
 static UA_Int32 TL_handleOpen(UA_TL_Connection1 connection, const UA_ByteString* msg, UA_Int32* pos) {
+	UA_Int32 retval = UA_SUCCESS;
 	UA_Int32 state;
-	UA_TL_Connection_getState(connection,&state);
 	SL_secureChannel *channel;
 
-
-
 	UA_ByteString receiverCertificateThumbprint;
 	UA_ByteString securityPolicyUri;
 	UA_ByteString senderCertificate;
 
-	if (state == CONNECTIONSTATE_ESTABLISHED) {
-
-//TODO get this from initialization
-		UA_alloc((void**)&receiverCertificateThumbprint.data, -1);
-		UA_alloc((void**)&securityPolicyUri.data, 47);
-		UA_alloc((void**)&senderCertificate.data, 0);
-
-		receiverCertificateThumbprint.data = UA_NULL;
-		receiverCertificateThumbprint.length = 0;
-
-		UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None",(UA_String*)&securityPolicyUri);
-		securityPolicyUri.length = 47;
+/*TODO place this into a initialization routine, get this from the "stack"-object*/
+	retval |= TL_securitySettingsMockup_get(&receiverCertificateThumbprint, &securityPolicyUri, &senderCertificate);
 
-		senderCertificate.data = UA_NULL;
-		senderCertificate.length = 0;
-
-		SL_Channel_new(&channel,
+	retval |= UA_TL_Connection_getState(connection,&state);
+	if (state == CONNECTIONSTATE_ESTABLISHED) {
+		retval |= SL_Channel_new(&channel,
 				SL_ChannelManager_generateChannelId,
 				SL_ChannelManager_generateToken,
 				&receiverCertificateThumbprint,
@@ -151,18 +151,17 @@ static UA_Int32 TL_handleOpen(UA_TL_Connection1 connection, const UA_ByteString*
 				&senderCertificate,
 				UA_SECURITYMODE_INVALID);
 
-
-	//return SL_Channel_new(connection, msg, pos);
-	//UA_TL_Connection_getId(connection,connectionId);
-		if(SL_Channel_initByRequest(*channel,connection, msg, pos) == UA_SUCCESS)
-		{
-			SL_ProcessOpenChannel(*channel, msg, pos);
-			SL_ChannelManager_addChannel(channel);
-		}else
-		{
+		if(SL_Channel_initByRequest(*channel,connection, msg, pos) == UA_SUCCESS){
+			retval |= SL_ProcessOpenChannel(*channel, msg, pos);
+			retval |= SL_ChannelManager_addChannel(channel);
+			return retval;
+		}else{
 			printf("TL_handleOpen - ERROR: could not create new secureChannel");
 		}
 	}
+	else{
+		printf("TL_handleOpen - ERROR: wrong ConnectionState");
+	}
 
 	return UA_ERR_INVALID_VALUE;
 }

+ 9 - 0
src/ua_transport_binary.h

@@ -6,6 +6,15 @@
 #include "ua_transport_binary.h"
 #include "ua_transport_connection.h"
 
+//transport errors begin at 1000
+#define UA_ERROR_MULTIPLE_HEL 1000
+#define UA_ERROR_RCV_ERROR 1001
+
+//variables which belong to layer
+#define TL_SERVER_PROTOCOL_VERSION  0
+#define TL_SERVER_MAX_CHUNK_COUNT 1
+#define TL_SERVER_MAX_MESSAGE_SIZE  8192
+
 
 /* Transport Layer Connection */
 //struct TL_Connection_T; // forward declaration

+ 2 - 46
src/ua_transport_binary_secure.c

@@ -237,6 +237,7 @@ UA_Int32 SL_handleRequest(SL_secureChannel channel, const UA_ByteString* msg,
 		UA_ResponseHeader_encodeBinary(&r, pos, &response_msg);
 		responsetype = UA_RESPONSEHEADER_NS0;
 	}
+
 	SL_Send(channel, &response_msg, responsetype);
 	UA_ByteString_deleteMembers(&response_msg);
 
@@ -248,52 +249,7 @@ UA_Int32 SL_ProcessOpenChannel(SL_secureChannel channel, const UA_ByteString* ms
 {
 	return SL_handleRequest(channel, msg, pos);
 }
-/**
- *
- * @param connection
- * @param msg
- * @param pos
- * @return
- */
-//UA_Int32 SL_Channel_new(TL_Connection *connection, const UA_ByteString* msg,
-//		UA_Int32* pos)
-//{
-//	DBG_VERBOSE(printf("SL_Channel_new - entered\n"));
-//	UA_Int32 retval = UA_SUCCESS;
-//
-//	/* Create New Channel*/
-//	SL_Channel *channel = &slc; // FIXME: generate new secure channel
-//	UA_AsymmetricAlgorithmSecurityHeader_init(&(channel->localAsymAlgSettings));
-//	UA_ByteString_copy(&UA_ByteString_securityPoliceNone,
-//			&(channel->localAsymAlgSettings.securityPolicyUri));
-//	UA_alloc((void** )&(channel->localNonce.data), sizeof(UA_Byte));
-//	channel->localNonce.length = 1;
-//	channel->connectionState = CONNECTIONSTATE_CLOSED; // the state of the channel will be opened in the service
-//	channel->sequenceHeader.requestId = 0;
-//	channel->sequenceHeader.sequenceNumber = 1;
-//	UA_String_init(&(channel->secureChannelId));
-//	channel->securityMode = UA_SECURITYMODE_INVALID;
-//	channel->securityToken.secureChannelId = 25; //TODO set a valid start secureChannelId number
-//	channel->securityToken.tokenId.tokenId = 1; //TODO set a valid start TokenId
-//	connection->secureChannel = channel;
-//	connection->secureChannel->tlConnection = connection;
-/* Read the OPN message headers */
-//	*pos += 4; // skip the securechannelid
-//	UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(msg, pos,
-//			&connection->secureChannel->remoteAsymAlgSettings);
-//	UA_SequenceHeader_decodeBinary(msg, pos,
-//			&connection->secureChannel->sequenceHeader);
-//	//TODO check that the sequence number is smaller than MaxUInt32 - 1024
-//	//TODO check if a OpenSecureChannelRequest follows
-//	retval |= SL_handleRequest(channel, msg, pos);
-//	return retval;
-// FIXME: reject
-//}
-/**
- * process the rest of the header. TL already processed MessageType
- * (OPN,MSG,...), isFinal and MessageSize. SL_process cares for
- * secureChannelId, XASHeader and sequenceHeader
- * */
+
 UA_Int32 SL_Process(const UA_ByteString* msg,
 		UA_Int32* pos)
 {

+ 1 - 1
src/ua_transport_binary_secure.h

@@ -5,7 +5,7 @@
 #include "ua_transport_binary.h"
 #include "ua_stack_channel.h"
 #include "ua_stack_channel_manager.h"
-#define UA_ERROR_MULTIPLE_HEL 1001
+
 /*inputs for secure Channel which must be provided once
 endPointUrl
 securityPolicyUrl

+ 0 - 6
src/ua_transport_connection.c

@@ -26,12 +26,6 @@ UA_Int32 UA_TL_Connection_new(UA_TL_Connection1 *connection, TL_Buffer localBuff
 	{
 		(*((TL_Connection**)connection))->localConf = localBuffers;
 		(*((TL_Connection**)connection))->writer = writer;
-
-	//	((TL_Connection*)connection)->localConf.maxChunkCount = localBuffers->maxChunkCount;
-	//	((TL_Connection*)connection)->localConf.maxMessageSize = localBuffers->maxMessageSize;
-	//	((TL_Connection*)connection)->localConf.protocolVersion = localBuffers->protocolVersion;
-	//	((TL_Connection*)connection)->localConf.recvBufferSize = localBuffers->recvBufferSize;
-	//	((TL_Connection*)connection)->localConf.sendBufferSize = localBuffers->sendBufferSize;
 	}
 	return retval;
 }

Plik diff jest za duży
+ 1145 - 0
src/ua_xml.c


+ 117 - 0
src/ua_xml.h

@@ -0,0 +1,117 @@
+/*
+ * ua_xml.h
+ *
+ *  Created on: 03.05.2014
+ *      Author: mrt
+ */
+
+#ifndef __UA_XML_H__
+#define __UA_XML_H__
+
+#include <expat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // strlen
+#include <ctype.h> // isspace
+#include <unistd.h> // read
+
+#include "opcua.h"
+#include "ua_namespace.h"
+
+UA_Int32 UA_Boolean_copycstring(cstring src, UA_Boolean* dst);
+UA_Int32 UA_Int16_copycstring(cstring src, UA_Int16* dst);
+UA_Int32 UA_UInt16_copycstring(cstring src, UA_UInt16* dst) ;
+UA_Boolean UA_NodeId_isBuiltinType(UA_NodeId* nodeid);
+void print_node(UA_Node const * node);
+
+/** @brief an object to hold a typed array */
+typedef struct UA_TypedArray {
+	UA_Int32 size;
+	UA_VTable* vt;
+	void** elements;
+} UA_TypedArray;
+
+/** @brief init typed array with size=-1 and an UA_INVALIDTYPE */
+UA_Int32 UA_TypedArray_init(UA_TypedArray* p);
+
+/** @brief allocate memory for the array header only */
+UA_Int32 UA_TypedArray_new(UA_TypedArray** p);
+UA_Int32 UA_TypedArray_setType(UA_TypedArray* p, UA_Int32 type);
+UA_Int32 UA_TypedArray_decodeXML(XML_Stack* s, XML_Attr* attr, UA_TypedArray* dst, _Bool isStart);
+
+UA_Int32 UA_NodeSetAlias_init(UA_NodeSetAlias* p);
+UA_Int32 UA_NodeSetAlias_new(UA_NodeSetAlias** p);
+UA_Int32 UA_NodeSetAlias_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAlias* dst, _Bool isStart);
+
+UA_Int32 UA_NodeSetAliases_init(UA_NodeSetAliases* p);
+UA_Int32 UA_NodeSetAliases_new(UA_NodeSetAliases** p);
+UA_Int32 UA_NodeSetAliases_println(cstring label, UA_NodeSetAliases *p);
+UA_Int32 UA_NodeSetAliases_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAliases* dst, _Bool isStart);
+
+typedef struct UA_NodeSet {
+	Namespace* ns;
+	UA_NodeSetAliases aliases;
+} UA_NodeSet;
+
+/** @brief init typed array with size=-1 and an UA_INVALIDTYPE */
+UA_Int32 UA_NodeSet_init(UA_NodeSet* p, UA_UInt32 nsid);
+UA_Int32 UA_NodeSet_new(UA_NodeSet** p, UA_UInt32 nsid);
+UA_Int32 UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases);
+UA_Int32 UA_NodeSet_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSet* dst, _Bool isStart);
+
+UA_Int32 UA_ExpandedNodeId_copycstring(cstring src, UA_ExpandedNodeId* dst, UA_NodeSetAliases* aliases);
+
+void XML_Stack_init(XML_Stack* p, UA_UInt32 nsid, cstring name);
+void XML_Stack_print(XML_Stack* s);
+
+/** @brief add a reference to a handler (@see XML_Stack_addChildHandler) for text data
+ *
+ * Assume a XML structure such as
+ *     <LocalizedText>
+ *          <Locale></Locale>
+ *          <Text>Server</Text>
+ *     </LocalizedText>
+ * which might be abbreviated as
+ *     <LocalizedText>Server</LocalizedText>
+ *
+ * We would add two (@ref XML_Stack_addChildHandler), one for Locale (index 0) and one for Text (index 1),
+ * both to be handled by (@ref UA_String_decodeXML) with elements "Data" and "Length". To handle the
+ * abbreviation we add
+ *   	XML_Stack_handleTextAsElementOf(s,"Data",1)
+ *
+ * @param[in] s the stack
+ * @param[in] textAttrib the name of the element of the handler at position textAttribIdx
+ * @param[in] textAttribIdx the index of the handler
+ */
+void XML_Stack_handleTextAsElementOf(XML_Stack* p, cstring textAttrib, unsigned int textAttribIdx);
+
+/** @brief make a handler known to the XML-stack on the current level
+ *
+ * The current level is given by s->depth, the maximum number of children is a predefined constant.
+ * A combination of type=UA_INVALIDTYPE and dst=UA_NULL is valid for special handlers only
+ *
+ * @param[in] s the stack
+ * @param[in] name the name of the element
+ * @param[in] nameLength the length of the element name
+ * @param[in] handler the decoder routine for this element
+ * @param[in] type the open62541-type of the element, UA_INVALIDTYPE if not in the VTable
+ * @param[out] dst the address of the object for the data, handlers will allocate object if UA_NULL
+ */
+void XML_Stack_addChildHandler(XML_Stack* p, cstring name, UA_Int32 nameLength, XML_decoder handler, UA_Int32 type, void* dst);
+
+void XML_Stack_startElement(void * data, const char *el, const char **attr);
+UA_Int32 XML_isSpace(cstring s, int len);
+void XML_Stack_handleText(void * data, const char *txt, int len);
+void XML_Stack_endElement(void *data, const char *el);
+
+/** @brief load a namespace from an XML-File
+ *
+ * @param[in/out] ns the address of the namespace ptr
+ * @param[in] namespaceId the numeric id of the namespace
+ * @param[in] rootName the name of the root element of the hierarchy (not used?)
+ * @param[in] fileName the name of an existing file, e.g. Opc.Ua.NodeSet2.xml
+ */
+UA_Int32 Namespace_loadFromFile(Namespace **ns,UA_UInt32 namespaceId,const char* rootName,const char* fileName);
+
+
+#endif // __UA_XML_H__

+ 1 - 1
tests/Makefile.am

@@ -3,7 +3,7 @@ TESTS=
 UNIT_TESTS=
 check_PROGRAMS=
 
-UNIT_TESTS += check_stack check_list check_indexedList check_builtin check_namespace check_memory
+UNIT_TESTS += check_stack check_list check_indexedList check_builtin check_namespace check_memory check_services_view
 TESTS += $(UNIT_TESTS)
 check_PROGRAMS += $(UNIT_TESTS)
 

+ 16 - 24
tests/check_builtin.c

@@ -1630,14 +1630,13 @@ START_TEST(UA_ApplicationDescription_copyShallWorkOnExample)
 	UA_ApplicationDescription *copiedValue = UA_NULL;
 
 	UA_Int32 retval = 0;
-
 	UA_String appString;
 	UA_String discString;
 	UA_String gateWayString;
 	UA_Int32 appSize = 3;
 	UA_Int32 discSize = 4;
 	UA_Int32 gateWaySize = 7;
-	UA_Int32 i = 0;
+	UA_Int32 i,j;
 	appString.data = UA_NULL;
 	discString.data = UA_NULL;
 	gateWayString.data = UA_NULL;
@@ -1665,30 +1664,20 @@ START_TEST(UA_ApplicationDescription_copyShallWorkOnExample)
 	gateWayString.data[6] = 'Y';
 	gateWayString.length = gateWaySize;
 
-
-	UA_String *pcopyString = UA_NULL;
-	UA_String *pgateArrayString = UA_NULL;
-	UA_String gateArrayString;
-	gateArrayString.data = UA_NULL;
-	UA_Int32 gateArraySize = 3;
-
-	UA_alloc((void**)&gateArrayString.data, gateArraySize);
-	gateArrayString.data[0] = '1';
-	gateArrayString.data[1] = '2';
-	gateArrayString.data[2] = '3';
-	gateArrayString.length = gateArraySize;
-	pgateArrayString = &gateArrayString;
-
+	UA_String **srcArray; UA_Array_new((void***)&srcArray,3,UA_STRING);
+	UA_String_copycstring("__open",srcArray[0]);
+	UA_String_copycstring("_62541",srcArray[1]);
+	UA_String_copycstring("opc ua",srcArray[2]);
 
 	UA_ApplicationDescription_new(&value);
-	value->discoveryUrlsSize = 3;
 	value->applicationUri.length = appString.length;
 	value->applicationUri.data = appString.data;
 	value->discoveryProfileUri.length = discString.length;
 	value->discoveryProfileUri.data = discString.data;
 	value->gatewayServerUri.length = gateWayString.length;
 	value->gatewayServerUri.data = gateWayString.data;
-	value->discoveryUrls = &pgateArrayString;
+	value->discoveryUrlsSize = 3;
+	value->discoveryUrls = srcArray;
 
 	UA_alloc((void**)&copiedValue,UA_ApplicationDescription_calcSize(UA_NULL));
 	//when
@@ -1712,14 +1701,17 @@ START_TEST(UA_ApplicationDescription_copyShallWorkOnExample)
 	}
 	ck_assert_int_eq(copiedValue->gatewayServerUri.length, value->gatewayServerUri.length);
 
-	//**String Test
-	pcopyString = *copiedValue->discoveryUrls;
-	for(i=0;i<gateArraySize;i++){
-		ck_assert_int_eq(pcopyString->data[i], pgateArrayString->data[i]);
+	//String Array Test
+	for(i=0;i<3;i++){
+		for(j=0;j<6;j++){
+			ck_assert_int_eq((value->discoveryUrls[i])->data[j],(copiedValue->discoveryUrls[i])->data[j]);
+		}
+		ck_assert_int_eq((value->discoveryUrls[i])->length,(copiedValue->discoveryUrls[i])->length);
 	}
-	ck_assert_int_eq(pcopyString->length, pgateArrayString->length);
-
+	ck_assert_int_eq((copiedValue->discoveryUrls[0])->data[2],'o');
+	ck_assert_int_eq((copiedValue->discoveryUrls[0])->data[3],'p');
 	ck_assert_int_eq(copiedValue->discoveryUrlsSize, value->discoveryUrlsSize);
+
 	//finally
 	UA_free(copiedValue);
 	UA_free(value);

+ 161 - 5
tests/check_namespace.c

@@ -5,9 +5,16 @@
 #include "ua_namespace.h"
 #include "check.h"
 
+int zeroCnt = 0;
+int visitCnt = 0;
+void checkZeroVisitor(const UA_Node* node) {
+	visitCnt++;
+	if (node == UA_NULL) zeroCnt++;
+}
+
 START_TEST(test_Namespace) {
 	Namespace *ns = UA_NULL;
-	Namespace_create(&ns, 512);
+	Namespace_new(&ns, 512, 0);
 	Namespace_delete(ns);
 }
 END_TEST
@@ -23,10 +30,10 @@ UA_Int32 createNode(UA_Node** p, UA_Int16 nsid, UA_Int32 id) {
 START_TEST(findNodeInNamespaceWithSingleEntry) {
 	// given
 	Namespace *ns;
-	Namespace_create(&ns, 512);
+	Namespace_new(&ns, 512, 0);
 	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
 	const UA_Node* nr = UA_NULL;
-	Namespace_Lock* nl = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
 	UA_Int32 retval;
 	// when
 	retval = Namespace_get(ns,&(n1->nodeId),&nr,&nl);
@@ -41,12 +48,12 @@ END_TEST
 START_TEST(findNodeInNamespaceWithTwoEntries) {
 	// given
 	Namespace *ns;
-	Namespace_create(&ns, 512);
+	Namespace_new(&ns, 512, 0);
 	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
 	UA_Node* n2; createNode(&n2,0,2255); Namespace_insert(ns,n2);
 
 	const UA_Node* nr = UA_NULL;
-	Namespace_Lock* nl = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
 	UA_Int32 retval;
 	// when
 	retval = Namespace_get(ns,&(n2->nodeId),&nr,&nl);
@@ -58,6 +65,145 @@ START_TEST(findNodeInNamespaceWithTwoEntries) {
 }
 END_TEST
 
+START_TEST(failToFindNodeInOtherNamespace) {
+	// given
+	Namespace *ns;
+	Namespace_new(&ns, 512, 0);
+	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
+	UA_Node* n2; createNode(&n2,0,2255); Namespace_insert(ns,n2);
+
+	const UA_Node* nr = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
+	UA_Int32 retval;
+	// when
+	UA_Node* n; createNode(&n,1,2255);
+	retval = Namespace_get(ns,&(n->nodeId),&nr,&nl);
+	// then
+	ck_assert_int_ne(retval, UA_SUCCESS);
+	// finally
+	UA_free(n);
+	Namespace_delete(ns);
+}
+END_TEST
+
+START_TEST(findNodeInNamespaceWithSeveralEntries) {
+	// given
+	Namespace *ns;
+	Namespace_new(&ns, 512, 0);
+	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
+	UA_Node* n2; createNode(&n2,0,2255); Namespace_insert(ns,n2);
+	UA_Node* n3; createNode(&n3,0,2257); Namespace_insert(ns,n3);
+	UA_Node* n4; createNode(&n4,0,2200); Namespace_insert(ns,n4);
+	UA_Node* n5; createNode(&n5,0,1); Namespace_insert(ns,n5);
+	UA_Node* n6; createNode(&n6,0,12); Namespace_insert(ns,n6);
+
+	const UA_Node* nr = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
+	UA_Int32 retval;
+	// when
+	retval = Namespace_get(ns,&(n3->nodeId),&nr,&nl);
+	// then
+	ck_assert_int_eq(retval, UA_SUCCESS);
+	ck_assert_ptr_eq(nr,n3);
+	// finally
+	Namespace_delete(ns);
+}
+END_TEST
+
+START_TEST(iterateOverNamespaceShallNotVisitEmptyNodes) {
+	// given
+	Namespace *ns;
+	Namespace_new(&ns, 512, 0);
+	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
+	UA_Node* n2; createNode(&n2,0,2255); Namespace_insert(ns,n2);
+	UA_Node* n3; createNode(&n3,0,2257); Namespace_insert(ns,n3);
+	UA_Node* n4; createNode(&n4,0,2200); Namespace_insert(ns,n4);
+	UA_Node* n5; createNode(&n5,0,1); Namespace_insert(ns,n5);
+	UA_Node* n6; createNode(&n6,0,12); Namespace_insert(ns,n6);
+
+	UA_Int32 retval;
+	// when
+	zeroCnt = 0;
+	visitCnt = 0;
+	retval = Namespace_iterate(ns,checkZeroVisitor);
+	// then
+	ck_assert_int_eq(retval, UA_SUCCESS);
+	ck_assert_int_eq(zeroCnt, 0);
+	ck_assert_int_eq(visitCnt, 6);
+	// finally
+	Namespace_delete(ns);
+}
+END_TEST
+
+START_TEST(findNodeInExpandedNamespace) {
+	// given
+	Namespace *ns;
+	Namespace_new(&ns, 10, 0);
+	UA_Node* n;
+	for (UA_Int32 i=0; i<200; i++) {
+		createNode(&n,0,i); Namespace_insert(ns,n);
+	}
+	const UA_Node* nr = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
+	UA_Int32 retval;
+	// when
+	createNode(&n,0,25);
+	retval = Namespace_get(ns,&(n->nodeId),&nr,&nl);
+	// then
+	ck_assert_int_eq(retval, UA_SUCCESS);
+	ck_assert_int_eq(nr->nodeId.identifier.numeric,n->nodeId.identifier.numeric);
+	// finally
+	UA_free(n);
+	Namespace_delete(ns);
+}
+END_TEST
+
+START_TEST(iterateOverExpandedNamespaceShallNotVisitEmptyNodes) {
+	// given
+	Namespace *ns;
+	Namespace_new(&ns, 10, 0);
+	UA_Node* n;
+	for (UA_Int32 i=0; i<200; i++) {
+		createNode(&n,0,i); Namespace_insert(ns,n);
+	}
+	// when
+	UA_Int32 retval;
+	zeroCnt = 0;
+	visitCnt = 0;
+	retval = Namespace_iterate(ns,checkZeroVisitor);
+	// then
+	ck_assert_int_eq(retval, UA_SUCCESS);
+	ck_assert_int_eq(zeroCnt, 0);
+	ck_assert_int_eq(visitCnt, 200);
+	// finally
+	Namespace_delete(ns);
+}
+END_TEST
+
+START_TEST(failToFindNonExistantNodeInNamespaceWithSeveralEntries) {
+	// given
+	Namespace *ns;
+	Namespace_new(&ns, 512, 0);
+	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
+	UA_Node* n2; createNode(&n2,0,2255); Namespace_insert(ns,n2);
+	UA_Node* n3; createNode(&n3,0,2257); Namespace_insert(ns,n3);
+	UA_Node* n4; createNode(&n4,0,2200); Namespace_insert(ns,n4);
+	UA_Node* n5; createNode(&n5,0,1); Namespace_insert(ns,n5);
+	UA_Node* n6; createNode(&n6,0,12);
+
+	const UA_Node* nr = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
+	UA_Int32 retval;
+	// when
+	retval = Namespace_get(ns,&(n6->nodeId),&nr,&nl);
+	// then
+	ck_assert_int_ne(retval, UA_SUCCESS);
+	// finally
+	UA_free(n6);
+	Namespace_delete(ns);
+}
+END_TEST
+
 Suite * namespace_suite (void) {
 	Suite *s = suite_create ("Namespace");
 
@@ -68,11 +214,21 @@ Suite * namespace_suite (void) {
 	TCase* tc_find = tcase_create ("Find");
 	tcase_add_test (tc_find, findNodeInNamespaceWithSingleEntry);
 	tcase_add_test (tc_find, findNodeInNamespaceWithTwoEntries);
+	tcase_add_test (tc_find, findNodeInNamespaceWithSeveralEntries);
+	tcase_add_test (tc_find, findNodeInExpandedNamespace);
+	tcase_add_test (tc_find, failToFindNonExistantNodeInNamespaceWithSeveralEntries);
+	tcase_add_test (tc_find, failToFindNodeInOtherNamespace);
 	suite_add_tcase (s, tc_find);
 
+	TCase* tc_iterate = tcase_create ("Iterate");
+	tcase_add_test (tc_find, iterateOverNamespaceShallNotVisitEmptyNodes);
+	tcase_add_test (tc_find, iterateOverExpandedNamespaceShallNotVisitEmptyNodes);
+	suite_add_tcase (s, tc_iterate);
+
 	return s;
 }
 
+
 int main (void) {
 	int number_failed =0;
 	Suite *s = namespace_suite ();

+ 65 - 0
tests/check_services_view.c

@@ -0,0 +1,65 @@
+/*
+ ============================================================================
+ Name        : check_stack.c
+ Author      :
+ Version     :
+ Copyright   : Your copyright notice
+ Description :
+ ============================================================================
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "opcua.h"
+#include "ua_services.h"
+#include "ua_statuscodes.h"
+#include "check.h"
+
+
+
+START_TEST(Service_TranslateBrowsePathsToNodeIds_SmokeTest)
+{
+	UA_TranslateBrowsePathsToNodeIdsRequest* request;
+	UA_TranslateBrowsePathsToNodeIdsRequest_new(&request);
+
+	UA_TranslateBrowsePathsToNodeIdsResponse* response;
+	UA_TranslateBrowsePathsToNodeIdsResponse_new(&response);
+
+	request->browsePathsSize = 1;
+	UA_Array_new((void***)&(request->browsePaths),request->browsePathsSize,UA_BROWSEPATH);
+
+	Service_TranslateBrowsePathsToNodeIds(UA_NULL,request,response);
+
+	ck_assert_int_eq(response->resultsSize,request->browsePathsSize);
+	ck_assert_int_eq(response->results[0]->statusCode,UA_STATUSCODE_BADQUERYTOOCOMPLEX);
+}
+END_TEST
+
+Suite* testSuite_Service_TranslateBrowsePathsToNodeIds()
+{
+	Suite *s = suite_create("Service_TranslateBrowsePathsToNodeIds");
+	TCase *tc_core = tcase_create("Core");
+	tcase_add_test(tc_core, Service_TranslateBrowsePathsToNodeIds_SmokeTest);
+	suite_add_tcase(s,tc_core);
+	return s;
+}
+
+int main (void)
+{
+	int number_failed = 0;
+
+	Suite *s;
+	SRunner *sr;
+
+
+	s = testSuite_Service_TranslateBrowsePathsToNodeIds();
+	sr = srunner_create(s);
+	srunner_run_all(sr,CK_NORMAL);
+	number_failed += srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+

+ 409 - 108
tests/check_stack.c

@@ -1,135 +1,450 @@
-/*
- ============================================================================
+/****************************************************************************
  Name        : check_stack.c
- Author      :
- Version     :
+ Author      : uleon @ open62541
+ Version     : 0.1
  Copyright   : Your copyright notice
- Description :
- ============================================================================
- */
+ Description : test cases to check different aspects of the
+ stack indication-response behavior w/o any network aspects
+
+
+```
+ Client            Server
+
+request  o--__
+              --> indication        +
+                                    | <---
+            __--o response          +
+confirm. <--
+```
+*****************************************************************************/
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "opcua.h"
 #include "ua_transport.h"
+#include "ua_transport_binary.h"
+#include "ua_transport_binary_secure.h"
 #include "check.h"
 
+#define MAXMSG 512
+#define BUFFER_SIZE 8192
 
-/*
-START_TEST(test_getPacketType_validParameter)
-{
+/** @brief this structure holds all the information for the stack test fixture */
+typedef struct stackTestFixture {
+	/** @brief the actual buffer to receive the response msg */
+	UA_Byte respMsgBuffer[BUFFER_SIZE];
+	/** @brief the management structure (initialized to point to respMsgBuffer in create */
+	UA_ByteString respMsg;
+	/** @brief the management data structure for the fake connection */
+	TL_Connection connection;
+} stackTestFixture;
 
-	char buf[] = {'C','L','O'};
-	UA_Int32 pos = 0;
-	UA_ByteString msg;
 
-	msg.data = buf;
-	msg.length = 3;
+/** @brief the maximum number of parallel fixtures.
+ * ( MAX_FIXTURES needs to match the number of bytes of fixturesMap )*/
+#define MAX_FIXTURES 32
+/** @brief this map marks the slots in fixtures as free (bit=0) or in use (bit=1) */
+UA_Int32 fixturesMap = 0;
+/** @brief the array of pointers to the fixtures */
+stackTestFixture* fixtures[MAX_FIXTURES];
 
-	ck_assert_int_eq(TL_getPacketType(&msg, &pos),packetType_CLO);
+/** @brief search first free handle, set and return */
+UA_Int32 stackTestFixture_getAndMarkFreeHandle() {
+	UA_Int32 freeFixtureHandle = 0;
+
+	for (freeFixtureHandle=0;freeFixtureHandle < MAX_FIXTURES;++freeFixtureHandle) {
+		if (!(fixturesMap & (1 << freeFixtureHandle))) { // when free
+			fixturesMap |= (1 << freeFixtureHandle); // then set
+			return freeFixtureHandle;
+		}
+	}
+	return UA_ERR_NO_MEMORY;
+}
+/** @brief clear bit in fixture map */
+UA_Int32 stackTestFixture_markHandleAsFree(UA_Int32 fixtureHandle) {
+	if (fixtureHandle >= 0 && fixtureHandle < MAX_FIXTURES) {
+		fixturesMap &= ~ (1 << fixtureHandle); // clear bit
+		return UA_SUCCESS;
+	}
+	return UA_ERR_INVALID_VALUE;
 }
-END_TEST
-*/
 
+/** @brief get a handle to a free slot and create a new stackTestFixture */
+UA_Int32 stackTestFixture_create(TL_Writer writerCallback) {
+	UA_UInt32 fixtureHandle = stackTestFixture_getAndMarkFreeHandle();
+	if (fixtureHandle < MAX_FIXTURES) {
+		UA_alloc((void**)&fixtures[fixtureHandle], sizeof(stackTestFixture));
+		stackTestFixture* fixture = fixtures[fixtureHandle];
+		fixture->respMsg.data = fixture->respMsgBuffer;
+		fixture->respMsg.length = 0;
+		fixture->connection.connectionState = CONNECTIONSTATE_CLOSED;
+		fixture->connection.writerCallback = writerCallback;
+		fixture->connection.localConf.maxChunkCount = 1;
+		fixture->connection.localConf.maxMessageSize = BUFFER_SIZE;
+		fixture->connection.localConf.protocolVersion = 0;
+		fixture->connection.localConf.recvBufferSize = BUFFER_SIZE;
+		fixture->connection.localConf.recvBufferSize = BUFFER_SIZE;
+		fixture->connection.connectionHandle = fixtureHandle;
+	}
+	return fixtureHandle;
+}
+/** @brief free the allocated memory of the stackTestFixture associated with the handle */
+UA_Int32 stackTestFixture_delete(UA_UInt32 fixtureHandle) {
+	if (fixtureHandle < MAX_FIXTURES) {
+		UA_free(fixtures[fixtureHandle]);
+		stackTestFixture_markHandleAsFree(fixtureHandle);
+		return UA_SUCCESS;
+	}
+	return UA_ERR_INVALID_VALUE;
+}
 
-/*
-START_TEST(decodeRequestHeader_test_validParameter)
-{
-		char testMessage = {0x00,0x00,0x72,0xf1,0xdc,0xc9,0x87,0x0b,
+/** @brief return the fixture associated with the handle */
+stackTestFixture* stackTestFixture_getFixture(UA_UInt32 fixtureHandle) {
+	if (fixtureHandle < MAX_FIXTURES && ( fixturesMap & (1 << fixtureHandle)))
+			return fixtures[fixtureHandle];
+	return UA_NULL;
+}
 
-							0xcf,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
-							0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,
-							0x00,0x00,0x00,0x00,0x00};
-		UA_ByteString rawMessage;
-		rawMessage.data = &testMessage;
-		rawMessage.length = 29;
-		Int32 position = 0;
-		T_RequestHeader requestHeader;
-		decodeRequestHeader(rawMessage,&position,&requestHeader);
+/** @brief write message provided in the gather buffers to the buffer of the fixture */
+UA_Int32 responseMsg(struct TL_Connection * c, UA_ByteString const ** gather_buf, UA_Int32 gather_len) {
+	UA_Int32 retval = UA_SUCCESS;
+	UA_UInt32 total_len = 0;
 
-		ck_assert_int_eq(requestHeader.authenticationToken.EncodingByte,0);
+	stackTestFixture* fixture = stackTestFixture_getFixture(c->connectionHandle);
 
-		ck_assert_int_eq(requestHeader.returnDiagnostics,0);
+	for (UA_Int32 i=0; i<gather_len && retval == UA_SUCCESS; ++i) {
+		if (total_len + gather_buf[i]->length < BUFFER_SIZE) {
+			memcpy(&(fixture->respMsg.data[total_len]),gather_buf[i]->data,gather_buf[i]->length);
+			total_len += gather_buf[i]->length;
+		} else {
+			retval = UA_ERR_NO_MEMORY;
+		}
+	}
+	fixture->respMsg.length = total_len;
+	return UA_SUCCESS;
+}
 
-		ck_assert_int_eq(requestHeader.authenticationToken.EncodingByte,0);
+void indicateMsg(UA_Int32 handle, UA_ByteString *slMessage) {
+	TL_Process(&(stackTestFixture_getFixture(handle)->connection), slMessage);
+}
 
+UA_Byte pkt_HEL[] = {
+            0x48, 0x45, 0x4c, 0x46, 0x39, 0x00, /*   HELF9. */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x01, 0x88, 0x13, 0x00, 0x00, 0x19, 0x00, /* ........ */
+0x00, 0x00, 0x6f, 0x70, 0x63, 0x2e, 0x74, 0x63, /* ..opc.tc */
+0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x30, 0x2e, 0x30, /* p://10.0 */
+0x2e, 0x35, 0x34, 0x2e, 0x37, 0x37, 0x3a, 0x34, /* .54.77:4 */
+0x38, 0x34, 0x32                                /* 842 */
+};
+UA_Byte pkt_OPN[] = {
+            0x4f, 0x50, 0x4e, 0x46, 0x85, 0x00, /*   OPNF.. */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, /* ....../. */
+0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, /* ..http:/ */
+0x2f, 0x6f, 0x70, 0x63, 0x66, 0x6f, 0x75, 0x6e, /* /opcfoun */
+0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6f, /* dation.o */
+0x72, 0x67, 0x2f, 0x55, 0x41, 0x2f, 0x53, 0x65, /* rg/UA/Se */
+0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x50, 0x6f, /* curityPo */
+0x6c, 0x69, 0x63, 0x79, 0x23, 0x4e, 0x6f, 0x6e, /* licy#Non */
+0x65, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* e....... */
+0xff, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, /* .3...... */
+0x00, 0x01, 0x00, 0xbe, 0x01, 0x00, 0x00, 0x40, /* .......@ */
+0xaf, 0xfc, 0xe8, 0xa1, 0x76, 0xcf, 0x01, 0x00, /* ....v... */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* ........ */
+0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x80, 0xee, 0x36, 0x00        /* .....6. */
+};
+
+UA_Byte pkt_MSG_CreateSession[] = {
+0x4d, 0x53, 0x47, 0x46, 0xb4, 0x05, 0x00, 0x00, /* MSGF.... */
+0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* QQ...... */  // assumes fixed secureChannelID=25 !
+0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, /* 4....... */
+0x01, 0x00, 0xcd, 0x01, 0x00, 0x00, 0x50, 0xd6, /* ......P. */
+0xfc, 0xe8, 0xa1, 0x76, 0xcf, 0x01, 0x01, 0x00, /* ...v.... */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, /* ........ */
+0xff, 0xff, 0x10, 0x27, 0x00, 0x00, 0x00, 0x00, /* ...'.... */
+0x00, 0x2d, 0x00, 0x00, 0x00, 0x75, 0x72, 0x6e, /* .-...urn */
+0x3a, 0x6d, 0x72, 0x74, 0x2d, 0x56, 0x69, 0x72, /* :mrt-Vir */
+0x74, 0x75, 0x61, 0x6c, 0x42, 0x6f, 0x78, 0x3a, /* tualBox: */
+0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, 0x41, /* UnifiedA */
+0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x6f, /* utomatio */
+0x6e, 0x3a, 0x55, 0x61, 0x45, 0x78, 0x70, 0x65, /* n:UaExpe */
+0x72, 0x74, 0x1e, 0x00, 0x00, 0x00, 0x75, 0x72, /* rt....ur */
+0x6e, 0x3a, 0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, /* n:Unifie */
+0x64, 0x41, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, /* dAutomat */
+0x69, 0x6f, 0x6e, 0x3a, 0x55, 0x61, 0x45, 0x78, /* ion:UaEx */
+0x70, 0x65, 0x72, 0x74, 0x02, 0x1b, 0x00, 0x00, /* pert.... */
+0x00, 0x55, 0x6e, 0x69, 0x66, 0x69, 0x65, 0x64, /* .Unified */
+0x20, 0x41, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, /*  Automat */
+0x69, 0x6f, 0x6e, 0x20, 0x55, 0x61, 0x45, 0x78, /* ion UaEx */
+0x70, 0x65, 0x72, 0x74, 0x01, 0x00, 0x00, 0x00, /* pert.... */
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, /* ........ */
+0x19, 0x00, 0x00, 0x00, 0x6f, 0x70, 0x63, 0x2e, /* ....opc. */
+0x74, 0x63, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x30, /* tcp://10 */
+0x2e, 0x30, 0x2e, 0x35, 0x34, 0x2e, 0x37, 0x37, /* .0.54.77 */
+0x3a, 0x34, 0x38, 0x34, 0x32, 0x2d, 0x00, 0x00, /* :4842-.. */
+0x00, 0x75, 0x72, 0x6e, 0x3a, 0x6d, 0x72, 0x74, /* .urn:mrt */
+0x2d, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, /* -Virtual */
+0x42, 0x6f, 0x78, 0x3a, 0x55, 0x6e, 0x69, 0x66, /* Box:Unif */
+0x69, 0x65, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x6d, /* iedAutom */
+0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x55, 0x61, /* ation:Ua */
+0x45, 0x78, 0x70, 0x65, 0x72, 0x74, 0x20, 0x00, /* Expert . */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
+0x00, 0x00, 0x72, 0x04, 0x00, 0x00, 0x30, 0x82, /* ..r...0. */
+0x04, 0x6e, 0x30, 0x82, 0x03, 0xd7, 0xa0, 0x03, /* .n0..... */
+0x02, 0x01, 0x02, 0x02, 0x04, 0x53, 0x1b, 0x10, /* .....S.. */
+0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, /* .0...*.H */
+0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, /* ........ */
+0x30, 0x81, 0x93, 0x31, 0x0b, 0x30, 0x09, 0x06, /* 0..1.0.. */
+0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, /* .U....DE */
+0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, /* 1.0...U. */
+0x08, 0x13, 0x08, 0x41, 0x6e, 0x79, 0x77, 0x68, /* ...Anywh */
+0x65, 0x72, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, /* ere1.0.. */
+0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x41, 0x6e, /* .U....An */
+0x79, 0x77, 0x68, 0x65, 0x72, 0x65, 0x31, 0x13, /* ywhere1. */
+0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, /* 0...U... */
+0x0a, 0x54, 0x55, 0x20, 0x44, 0x72, 0x65, 0x73, /* .TU Dres */
+0x64, 0x65, 0x6e, 0x31, 0x36, 0x30, 0x34, 0x06, /* den1604. */
+0x03, 0x55, 0x04, 0x0b, 0x13, 0x2d, 0x43, 0x68, /* .U...-Ch */
+0x61, 0x69, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, /* air for  */
+0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, /* Process  */
+0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, /* Control  */
+0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, /* Systems  */
+0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, /* Engineer */
+0x69, 0x6e, 0x67, 0x31, 0x11, 0x30, 0x0f, 0x06, /* ing1.0.. */
+0x03, 0x55, 0x04, 0x03, 0x13, 0x08, 0x55, 0x61, /* .U....Ua */
+0x45, 0x78, 0x70, 0x65, 0x72, 0x74, 0x30, 0x1e, /* Expert0. */
+0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x30, 0x38, /* ..140308 */
+0x31, 0x32, 0x34, 0x34, 0x31, 0x35, 0x5a, 0x17, /* 124415Z. */
+0x0d, 0x31, 0x34, 0x30, 0x33, 0x30, 0x38, 0x31, /* .1403081 */
+0x33, 0x34, 0x34, 0x31, 0x35, 0x5a, 0x30, 0x81, /* 34415Z0. */
+0x93, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, /* .1.0...U */
+0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, 0x11, /* ....DE1. */
+0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, /* 0...U... */
+0x08, 0x41, 0x6e, 0x79, 0x77, 0x68, 0x65, 0x72, /* .Anywher */
+0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, /* e1.0...U */
+0x04, 0x07, 0x13, 0x08, 0x41, 0x6e, 0x79, 0x77, /* ....Anyw */
+0x68, 0x65, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, /* here1.0. */
+0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x54, /* ..U....T */
+0x55, 0x20, 0x44, 0x72, 0x65, 0x73, 0x64, 0x65, /* U Dresde */
+0x6e, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, 0x55, /* n1604..U */
+0x04, 0x0b, 0x13, 0x2d, 0x43, 0x68, 0x61, 0x69, /* ...-Chai */
+0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, 0x72, /* r for Pr */
+0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x43, 0x6f, /* ocess Co */
+0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x53, 0x79, /* ntrol Sy */
+0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, 0x6e, /* stems En */
+0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, /* gineerin */
+0x67, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, /* g1.0...U */
+0x04, 0x03, 0x13, 0x08, 0x55, 0x61, 0x45, 0x78, /* ....UaEx */
+0x70, 0x65, 0x72, 0x74, 0x30, 0x81, 0x9f, 0x30, /* pert0..0 */
+0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, /* ...*.H.. */
+0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, /* ........ */
+0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, /* ..0..... */
+0x00, 0xb3, 0xb3, 0xc9, 0x97, 0xb7, 0x4f, 0x6d, /* ......Om */
+0x6f, 0x72, 0x48, 0xe2, 0x5f, 0x8c, 0x89, 0x0f, /* orH._... */
+0xc3, 0x47, 0x17, 0x4c, 0xd2, 0x8c, 0x2a, 0x85, /* .G.L..*. */
+0xf6, 0x80, 0xb1, 0x9e, 0xf4, 0x90, 0xff, 0x0f, /* ........ */
+0xff, 0x42, 0x74, 0x75, 0xcd, 0xd5, 0xe0, 0x8f, /* .Btu.... */
+0x7f, 0xa1, 0x41, 0x86, 0x83, 0xcf, 0x2c, 0xef, /* ..A...,. */
+0xbd, 0xb7, 0xbf, 0x50, 0xa9, 0x5c, 0xfa, 0x39, /* ...P.\.9 */
+0x84, 0xbb, 0x7e, 0xc9, 0x7e, 0x5b, 0xc8, 0x1b, /* ..~.~[.. */
+0x19, 0xfc, 0x31, 0x05, 0xa9, 0x0c, 0x31, 0x3c, /* ..1...1< */
+0x1a, 0x86, 0x50, 0x17, 0x45, 0x0a, 0xfd, 0xfe, /* ..P.E... */
+0xa0, 0xc4, 0x88, 0x93, 0xff, 0x1c, 0xf3, 0x60, /* .......` */
+0x06, 0xc6, 0xdf, 0x7c, 0xc6, 0xcd, 0x95, 0x7d, /* ...|...} */
+0xf8, 0x3b, 0x7a, 0x53, 0x15, 0xbb, 0x2e, 0xcf, /* .;zS.... */
+0xd1, 0x63, 0xae, 0x5a, 0x30, 0x48, 0x67, 0x5f, /* .c.Z0Hg_ */
+0xa8, 0x30, 0x7f, 0x35, 0xe4, 0x43, 0x94, 0xa3, /* .0.5.C.. */
+0xc1, 0xfe, 0x69, 0xcd, 0x5c, 0xd7, 0x88, 0xc0, /* ..i.\... */
+0xa5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, /* ........ */
+0x01, 0xcb, 0x30, 0x82, 0x01, 0xc7, 0x30, 0x0c, /* ..0...0. */
+0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, /* ..U..... */
+0x04, 0x02, 0x30, 0x00, 0x30, 0x50, 0x06, 0x09, /* ..0.0P.. */
+0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, /* `.H...B. */
+0x0d, 0x04, 0x43, 0x16, 0x41, 0x22, 0x47, 0x65, /* ..C.A"Ge */
+0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, /* nerated  */
+0x77, 0x69, 0x74, 0x68, 0x20, 0x55, 0x6e, 0x69, /* with Uni */
+0x66, 0x69, 0x65, 0x64, 0x20, 0x41, 0x75, 0x74, /* fied Aut */
+0x6f, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, /* omation  */
+0x55, 0x41, 0x20, 0x42, 0x61, 0x73, 0x65, 0x20, /* UA Base  */
+0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x20, /* Library  */
+0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4f, 0x70, /* using Op */
+0x65, 0x6e, 0x53, 0x53, 0x4c, 0x22, 0x30, 0x1d, /* enSSL"0. */
+0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, /* ..U..... */
+0x14, 0x37, 0x39, 0x34, 0x93, 0xa2, 0x65, 0xef, /* .794..e. */
+0xb9, 0xd4, 0x71, 0x21, 0x4b, 0x77, 0xdb, 0x28, /* ..q!Kw.( */
+0xc8, 0xfa, 0x03, 0xfe, 0x05, 0x30, 0x81, 0xc3, /* .....0.. */
+0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xbb, /* ..U.#... */
+0x30, 0x81, 0xb8, 0x80, 0x14, 0x37, 0x39, 0x34, /* 0....794 */
+0x93, 0xa2, 0x65, 0xef, 0xb9, 0xd4, 0x71, 0x21, /* ..e...q! */
+0x4b, 0x77, 0xdb, 0x28, 0xc8, 0xfa, 0x03, 0xfe, /* Kw.(.... */
+0x05, 0xa1, 0x81, 0x99, 0xa4, 0x81, 0x96, 0x30, /* .......0 */
+0x81, 0x93, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, /* ..1.0... */
+0x55, 0x04, 0x06, 0x13, 0x02, 0x44, 0x45, 0x31, /* U....DE1 */
+0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x08, /* .0...U.. */
+0x13, 0x08, 0x41, 0x6e, 0x79, 0x77, 0x68, 0x65, /* ..Anywhe */
+0x72, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, /* re1.0... */
+0x55, 0x04, 0x07, 0x13, 0x08, 0x41, 0x6e, 0x79, /* U....Any */
+0x77, 0x68, 0x65, 0x72, 0x65, 0x31, 0x13, 0x30, /* where1.0 */
+0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, /* ...U.... */
+0x54, 0x55, 0x20, 0x44, 0x72, 0x65, 0x73, 0x64, /* TU Dresd */
+0x65, 0x6e, 0x31, 0x36, 0x30, 0x34, 0x06, 0x03, /* en1604.. */
+0x55, 0x04, 0x0b, 0x13, 0x2d, 0x43, 0x68, 0x61, /* U...-Cha */
+0x69, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, /* ir for P */
+0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x43, /* rocess C */
+0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x53, /* ontrol S */
+0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x45, /* ystems E */
+0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, /* ngineeri */
+0x6e, 0x67, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, /* ng1.0... */
+0x55, 0x04, 0x03, 0x13, 0x08, 0x55, 0x61, 0x45, /* U....UaE */
+0x78, 0x70, 0x65, 0x72, 0x74, 0x82, 0x04, 0x53, /* xpert..S */
+0x1b, 0x10, 0x9f, 0x30, 0x0e, 0x06, 0x03, 0x55, /* ...0...U */
+0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, /* ........ */
+0x02, 0x02, 0xf4, 0x30, 0x20, 0x06, 0x03, 0x55, /* ...0 ..U */
+0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, /* .%.....0 */
+0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, /* ...+.... */
+0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, /* .....+.. */
+0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x4e, 0x06, /* .....0N. */
+0x03, 0x55, 0x1d, 0x11, 0x04, 0x47, 0x30, 0x45, /* .U...G0E */
+0x86, 0x2d, 0x75, 0x72, 0x6e, 0x3a, 0x6d, 0x72, /* .-urn:mr */
+0x74, 0x2d, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, /* t-Virtua */
+0x6c, 0x42, 0x6f, 0x78, 0x3a, 0x55, 0x6e, 0x69, /* lBox:Uni */
+0x66, 0x69, 0x65, 0x64, 0x41, 0x75, 0x74, 0x6f, /* fiedAuto */
+0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x55, /* mation:U */
+0x61, 0x45, 0x78, 0x70, 0x65, 0x72, 0x74, 0x82, /* aExpert. */
+0x0e, 0x6d, 0x72, 0x74, 0x2d, 0x56, 0x69, 0x72, /* .mrt-Vir */
+0x74, 0x75, 0x61, 0x6c, 0x42, 0x6f, 0x78, 0x87, /* tualBox. */
+0x04, 0xc0, 0xa8, 0x02, 0x73, 0x30, 0x0d, 0x06, /* ....s0.. */
+0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, /* .*.H.... */
+0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, /* ........ */
+0x77, 0x2c, 0x9c, 0x23, 0x60, 0x13, 0x3f, 0xa5, /* w,.#`.?. */
+0xc8, 0xb3, 0x20, 0x27, 0x64, 0xda, 0x7f, 0xaa, /* .. 'd... */
+0xc5, 0x86, 0xfa, 0xd7, 0x24, 0x2e, 0xbe, 0xa0, /* ....$... */
+0xfc, 0x49, 0x8f, 0xc0, 0xef, 0xfb, 0x9a, 0xe6, /* .I...... */
+0x50, 0xe6, 0xb3, 0x53, 0x91, 0x91, 0x89, 0xd3, /* P..S.... */
+0x5a, 0xa5, 0xc9, 0x9c, 0xf6, 0x7b, 0x8f, 0x93, /* Z....{.. */
+0xb4, 0x98, 0xc3, 0x92, 0x26, 0x49, 0x8a, 0x96, /* ....&I.. */
+0x6e, 0x8f, 0xf5, 0x93, 0x48, 0x90, 0x9e, 0x7e, /* n...H..~ */
+0x1d, 0xad, 0x63, 0xbb, 0x5e, 0x1c, 0x0c, 0x86, /* ..c.^... */
+0x2d, 0xce, 0xe2, 0xe1, 0x87, 0x8d, 0x4c, 0x4b, /* -.....LK */
+0x89, 0x24, 0x77, 0xff, 0x62, 0x95, 0xf7, 0xec, /* .$w.b... */
+0x16, 0x7c, 0x8a, 0x1e, 0x4d, 0x89, 0xcb, 0x3d, /* .|..M..= */
+0xc8, 0xc0, 0x7c, 0x12, 0x5a, 0x29, 0xf2, 0xe7, /* ..|.Z).. */
+0x68, 0xf9, 0xb9, 0x85, 0xe5, 0xc0, 0x46, 0xac, /* h.....F. */
+0x89, 0xdb, 0xd0, 0x87, 0xaa, 0xa1, 0x7a, 0x73, /* ......zs */
+0x71, 0xcc, 0x8e, 0x01, 0x80, 0xf3, 0x07, 0x70, /* q......p */
+0x00, 0x00, 0x00, 0x00, 0x80, 0x4f, 0x32, 0x41, /* .....O2A */
+0xff, 0xff, 0xff, 0xff                          /* .... */
+};
+
+START_TEST(emptyIndicationShallYieldNoResponse)
+{
+	// given
+	UA_Int32 handle = stackTestFixture_create(responseMsg);
+	UA_ByteString message = { -1, (UA_Byte*) UA_NULL };
+
+	// when
+	indicateMsg(handle, &message);
+
+	// then
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.length,0);
+
+	// finally
+	stackTestFixture_delete(handle);
 }
 END_TEST
-*/
 
-START_TEST(encode_builtInDatatypeArray_test_String)
+
+START_TEST(validHELIndicationShallYieldACKResponse)
 {
-	UA_Int32 noElements = 2;
-	UA_ByteString s1 = { 6, (UA_Byte*) "OPC UA" };
-	UA_ByteString s2 = { -1, UA_NULL };
-	UA_ByteString* array[] = { &s1, &s2	};
-	UA_Int32 pos = 0;
-	UA_Byte buf[256];
-	UA_ByteString dst = { sizeof(buf), buf };
-	UA_Byte result[] = {
-			0x02, 0x00, 0x00, 0x00,		// noElements
-			0x06, 0x00, 0x00, 0x00,		// s1.Length
-			'O', 'P', 'C', ' ', 'U', 'A', // s1.Data
-			0xFF, 0xFF, 0xFF, 0xFF		// s2.Length
-	};
-
-	UA_Array_encodeBinary((void const**)array, noElements, UA_BYTESTRING, &pos, &dst);
-
-	// check size
-	ck_assert_int_eq(pos, 4 + 4 + 6 + 4);
-	ck_assert_int_eq(pos, sizeof(result));
-	// check result
-	ck_assert_int_eq(buf[0],result[0]);
-	ck_assert_int_eq(buf[1],result[1]);
-	ck_assert_int_eq(buf[2],result[2]);
-	ck_assert_int_eq(buf[3],result[3]);
-	ck_assert_int_eq(buf[4],result[4]);
-	ck_assert_int_eq(buf[5],result[5]);
-	ck_assert_int_eq(buf[6],result[6]);
-	ck_assert_int_eq(buf[7],result[7]);
-	ck_assert_int_eq(buf[8],result[8]);
-	ck_assert_int_eq(buf[9],result[9]);
-	ck_assert_int_eq(buf[10],result[10]);
-	ck_assert_int_eq(buf[11],result[11]);
-	ck_assert_int_eq(buf[12],result[12]);
-	ck_assert_int_eq(buf[13],result[13]);
-	ck_assert_int_eq(buf[14],result[14]);
-	ck_assert_int_eq(buf[15],result[15]);
-	ck_assert_int_eq(buf[16],result[16]);
-	ck_assert_int_eq(buf[17],result[17]);
+	// given
+	UA_Int32 handle = stackTestFixture_create(responseMsg);
+	UA_ByteString message_001 = { sizeof(pkt_HEL), pkt_HEL };
+
+	// when
+	indicateMsg(handle, &message_001);
+
+	// then
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.length,28);
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[0],'A');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[1],'C');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[2],'K');
+
+	// finally
+	stackTestFixture_delete(handle);
 }
 END_TEST
 
-/**Suite *testSuite_getPacketType(void)
+START_TEST(validOpeningSequenceShallCreateChannel)
 {
-	Suite *s = suite_create("getPacketType");
-	TCase *tc_core = tcase_create("Core");
-	tcase_add_test(tc_core,test_getPacketType_validParameter);
-	suite_add_tcase(s,tc_core);
-	return s;
-}**/
+	// given
+	UA_Int32 handle = stackTestFixture_create(responseMsg);
+
+	UA_ByteString message_001 = { sizeof(pkt_HEL), pkt_HEL };
+	UA_ByteString message_002 = { sizeof(pkt_OPN), pkt_OPN };
+
+	// when
+	indicateMsg(handle, &message_001);
+	indicateMsg(handle, &message_002);
+
+	// then
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[0],'O');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[1],'P');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[2],'N');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->connection.connectionState, CONNECTIONSTATE_ESTABLISHED);
+
+	// finally
+	stackTestFixture_delete(handle);
+}
+END_TEST
 
-Suite* testSuite_encode_builtInDatatypeArray()
+START_TEST(validCreateSessionShallCreateSession)
 {
-	Suite *s = suite_create("encode_builtInDatatypeArray");
-	TCase *tc_core = tcase_create("Core");
-	tcase_add_test(tc_core, encode_builtInDatatypeArray_test_String);
-	suite_add_tcase(s,tc_core);
-	return s;
+	// given
+	UA_Int32 handle = stackTestFixture_create(responseMsg);
+
+	UA_ByteString message_001 = { sizeof(pkt_HEL), pkt_HEL };
+	UA_ByteString message_002 = { sizeof(pkt_OPN), pkt_OPN };
+	UA_ByteString message_003 = { sizeof(pkt_MSG_CreateSession), pkt_MSG_CreateSession };
+
+	// when
+	indicateMsg(handle, &message_001);
+	indicateMsg(handle, &message_002);
+	UA_Int32 pos = 8;
+	UA_UInt32 secureChannelId = stackTestFixture_getFixture(handle)->connection.secureChannel->securityToken.secureChannelId;
+	UA_UInt32_encodeBinary(&secureChannelId,&pos,&message_003);
+	indicateMsg(handle, &message_003);
+
+	// then
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[0],'M');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[1],'S');
+	ck_assert_int_eq(stackTestFixture_getFixture(handle)->respMsg.data[2],'G');
+	ck_assert_ptr_ne(stackTestFixture_getFixture(handle)->connection.secureChannel, UA_NULL);
+
+	// finally
+	stackTestFixture_delete(handle);
 }
+END_TEST
 
-/*
-Suite* TL_<TESTSUITENAME>(void)
+Suite* testSuite()
 {
-	Suite *s = suite_create("<TESTSUITENAME>");
+	Suite *s = suite_create("Stack Test");
 	TCase *tc_core = tcase_create("Core");
-	tcase_add_test(tc_core,<TEST_NAME>);
+	tcase_add_test(tc_core, emptyIndicationShallYieldNoResponse);
+	tcase_add_test(tc_core, validHELIndicationShallYieldACKResponse);
+	tcase_add_test(tc_core, validOpeningSequenceShallCreateChannel);
+	tcase_add_test(tc_core, validCreateSessionShallCreateSession);
 	suite_add_tcase(s,tc_core);
 	return s;
 }
-*/
-
 
 int main (void)
 {
@@ -138,27 +453,13 @@ int main (void)
 	Suite *s;
 	SRunner *sr;
 
-	/* s = testSuite_getPacketType();
-	sr = srunner_create(s);
-	srunner_run_all(sr,CK_NORMAL);
-	number_failed = srunner_ntests_failed(sr);
-	srunner_free(sr); */
-
-	s = testSuite_encode_builtInDatatypeArray();
+	s = testSuite();
 	sr = srunner_create(s);
 	srunner_run_all(sr,CK_NORMAL);
 	number_failed += srunner_ntests_failed(sr);
 	srunner_free(sr);
 
-	/* <TESTSUITE_TEMPLATE>
-	s =  <TESTSUITENAME>;
-	sr = srunner_create(s);
-	srunner_run_all(sr,CK_NORMAL);
-	number_failed += srunner_ntests_failed(sr);
-	srunner_free(sr);
-	*/
 	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-
 }
 
 

.coverity.sh → tools/.coverity.sh


+ 1 - 1
tools/Makefile.am

@@ -3,7 +3,7 @@ INCLUDE_DIR = $(top_builddir)/include
 AUTO_NAME = opcua
 NS0_NAME = ua_namespace_0
 
-all-local: $(AUTO_NAME).cgen $(AUTO_NAME).hgen $(NS0_NAME).cgen $(NS0_NAME).hgen
+all-local: $(AUTO_NAME).cgen $(AUTO_NAME).hgen $(NS0_NAME).cgen $(NS0_NAME).hgen $(bin_PROGRAMS)
 
 $(AUTO_NAME).cgen $(AUTO_NAME).hgen: Opc.Ua.Types.bsd generate_builtin.py
 	python generate_builtin.py Opc.Ua.Types.bsd $(AUTO_NAME)

+ 134 - 139
tools/generate_builtin.py

@@ -8,30 +8,21 @@ import re
 from lxml import etree
 
 if len(sys.argv) != 3:
-    print("Usage: python generate_builtin.py <path/to/Opc.Ua.Types.bsd> <outfile w/o extension>", file=sys.stdout)
-    exit(0)
+	print("Usage: python generate_builtin.py <path/to/Opc.Ua.Types.bsd> <outfile w/o extension>", file=sys.stdout)
+	exit(0)
 
 # types that are coded manually 
 exclude_types = set(["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
-                    "Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid",
-                    "ByteString", "XmlElement", "NodeId", "ExpandedNodeId", "StatusCode", 
-                    "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
-                     "Variant", "DiagnosticInfo", "IntegerId"])
-
-elementary_size = dict()
-elementary_size["Boolean"] = 1;
-elementary_size["SByte"] = 1;
-elementary_size["Byte"] = 1;
-elementary_size["Int16"] = 2;
-elementary_size["UInt16"] = 2;
-elementary_size["Int32"] = 4;
-elementary_size["UInt32"] = 4;
-elementary_size["Int64"] = 8;
-elementary_size["UInt64"] = 8;
-elementary_size["Float"] = 4;
-elementary_size["Double"] = 8;
-elementary_size["DateTime"] = 8;
-elementary_size["StatusCode"] = 4;
+					"Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid",
+					"ByteString", "XmlElement", "NodeId", "ExpandedNodeId", "StatusCode", 
+					"QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
+					 "Variant", "DiagnosticInfo", "IntegerId"])
+
+# do not forget to get rid of these excludes once it works
+exclude_xml_decode = set(["UA_ReferenceNode", "UA_ObjectNode", "UA_ObjectTypeNode", "UA_VariableNode", "UA_VariableTypeNode", "UA_DataTypeNode"])
+
+elementary_size = {"Boolean":1, "SByte":1, "Byte":1, "Int16":2, "UInt16":2, "Int32":4, "UInt32":4,
+                   "Int64":8, "UInt64":8, "Float":4, "Double":8, "DateTime":8, "StatusCode":4}
 
 enum_types = []
 structured_types = []
@@ -44,20 +35,16 @@ def skipType(name):
     if re.search("NodeId$", name) != None:
         return True
     return False
-
+    
 def stripTypename(tn):
-    return tn[tn.find(":")+1:]
+	return tn[tn.find(":")+1:]
 
-def camlCase2AdaCase(item):
-    (newitem, n) = re.subn("(?<!^)(?<![A-Z])([A-Z])", "_\\1", item)
-    return newitem
-    
 def camlCase2CCase(item):
-    if item in ["Float","Double"]:
-        return "my" + item
-    return item[:1].lower() + item[1:] if item else ''
+	if item in ["Float","Double"]:
+		return "my" + item
+	return item[:1].lower() + item[1:] if item else ''
 
-# are the prerequisites in place? if not, postpone.
+# are the types we need already in place? if not, postpone.
 def printableStructuredType(element):
     for child in element:
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
@@ -66,14 +53,13 @@ def printableStructuredType(element):
                 return False
     return True
 
-# There three types of types in the bsd file:
+# There are three types of types in the bsd file:
 # StructuredType, EnumeratedType OpaqueType
 
-def createEnumerated(element):
+def createEnumerated(element):	
     valuemap = OrderedDict()
     name = "UA_" + element.get("Name")
     enum_types.append(name)
-    print("\n/** @name UA_" + name + " */", end='\n', file=fh)
     for child in element:
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
             print("/** @brief " + child.text + " */", end='\n', file=fh)
@@ -91,18 +77,19 @@ def createEnumerated(element):
     print("UA_TYPE_METHOD_INIT_AS("+name+", UA_UInt32)", end='\n', file=fc)
     print("UA_TYPE_METHOD_COPY_AS("+name+", UA_UInt32)",'\n', file=fc)  
     print("UA_TYPE_METHOD_NEW_DEFAULT("+name+")\n", end='\n', file=fc)
+    print("UA_TYPE_METHOD_DECODEXML_NOTIMPL("+name+")", end='\n', file=fc)
     return
     
 def createStructured(element):
     valuemap = OrderedDict()
     name = "UA_" + element.get("Name")
-    print("\n/** @name UA_" + name + " */", end='\n', file=fh)
+    print("\n/** @name " + name + " */\n", file=fh)
 
     lengthfields = set()
     for child in element:
-        if child.get("LengthField"):
-            lengthfields.add(child.get("LengthField"))
-    
+		if child.get("LengthField"):
+			lengthfields.add(child.get("LengthField"))
+	
     for child in element:
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
             print("/** @brief " + child.text + " */", end='\n', file=fh)
@@ -116,26 +103,21 @@ def createStructured(element):
             else:
                 valuemap[childname] = typename
 
-    # if "Response" in name[len(name)-9:]:
-    #    print("type " + name + " is new Response_Base with "),
-    # elif "Request" in name[len(name)-9:]:
-    #    print ("type " + name + " is new Request_Base with "),
-    # else:
-    #    print ("type " + name + " is new UA_Builtin with "),
-    print("typedef struct " + name + "_T {", end='\n', file=fh)
+    print("typedef struct " + name + " {", end='\n', file=fh)
     if len(valuemap) == 0:
-        typename = stripTypename(element.get("BaseType"))
-        childname = camlCase2CCase(typename)
-        valuemap[childname] = typename 
+		typename = stripTypename(element.get("BaseType"))
+		childname = camlCase2CCase(typename)
+		valuemap[childname] = typename 
     for n,t in valuemap.iteritems():
-        if t.find("**") != -1:
-            print("\t" + "UA_Int32 " + n + "Size;", end='\n', file=fh)
-        print("\t" + "UA_" + t + " " + n + ";", end='\n', file=fh)
+		if t.find("**") != -1:
+			print("\t" + "UA_Int32 " + n + "Size;", end='\n', file=fh)
+		print("\t" + "UA_" + t + " " + n + ";", end='\n', file=fh)
     print("} " + name + ";", end='\n', file=fh)
 
     print("UA_Int32 " + name + "_calcSize(" + name + " const* ptr);", end='\n', file=fh)
     print("UA_Int32 " + name + "_encodeBinary(" + name + " const* src, UA_Int32* pos, UA_ByteString* dst);", end='\n', file=fh)
     print("UA_Int32 " + name + "_decodeBinary(UA_ByteString const* src, UA_Int32* pos, " + name + "* dst);", end='\n', file=fh)
+    print("UA_Int32 " + name + "_decodeXML(XML_Stack* s, XML_Attr* attr, " + name + "* dst, _Bool isStart);", end='\n', file=fh)
     print("UA_Int32 " + name + "_delete("+ name + "* p);", end='\n', file=fh)
     print("UA_Int32 " + name + "_deleteMembers(" + name + "* p);", end='\n', file=fh)
     print("UA_Int32 " + name + "_init("+ name + " * p);", end='\n', file=fh)
@@ -146,41 +128,41 @@ def createStructured(element):
     print("\n\tif(ptr==UA_NULL){return sizeof("+ name +");}", end='', file=fc)
     print("\n\treturn 0", end='', file=fc)
 
-    # code _calcSize
+	# code _calcSize
     for n,t in valuemap.iteritems():
-        if t in elementary_size:
-            print('\n\t + sizeof(UA_' + t + ") // " + n, end='', file=fc)
-        else:
-            if t in enum_types:
-                print('\n\t + 4 //' + n, end='', file=fc) # enums are all 32 bit
-            elif t.find("**") != -1:
-		print("\n\t + 0 //" + n + "Size is included in UA_Array_calcSize", end='', file=fc),
-		print("\n\t + UA_Array_calcSize(ptr->" + n + "Size, UA_" + t[0:t.find("*")].upper() + ", (void const**) ptr->" + n +")", end='', file=fc)
-            elif t.find("*") != -1:
-                print('\n\t + ' + "UA_" + t[0:t.find("*")] + "_calcSize(ptr->" + n + ')', end='', file=fc)
-            else:
-                print('\n\t + ' + "UA_" + t + "_calcSize(&(ptr->" + n + '))', end='', file=fc)
+		if t in elementary_size:
+			print('\n\t + sizeof(UA_' + t + ") // " + n, end='', file=fc)
+		else:
+			if t in enum_types:
+				print('\n\t + 4 //' + n, end='', file=fc) # enums are all 32 bit
+			elif t.find("**") != -1:
+				print("\n\t + 0 //" + n + "Size is included in UA_Array_calcSize", end='', file=fc),
+				print("\n\t + UA_Array_calcSize(ptr->" + n + "Size, UA_" + t[0:t.find("*")].upper() + ", (void const**) ptr->" + n +")", end='', file=fc)
+			elif t.find("*") != -1:
+				print('\n\t + ' + "UA_" + t[0:t.find("*")] + "_calcSize(ptr->" + n + ')', end='', file=fc)
+			else:
+				print('\n\t + ' + "UA_" + t + "_calcSize(&(ptr->" + n + '))', end='', file=fc)
 
     print("\n\t;\n}\n", end='\n', file=fc)
 
     print("UA_Int32 "+name+"_encodeBinary("+name+" const * src, UA_Int32* pos, UA_ByteString* dst) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
-    # code _encode
+	# code _encode
     for n,t in valuemap.iteritems():
-        if t in elementary_size:
-            print('\tretval |= UA_'+t+'_encodeBinary(&(src->'+n+'),pos,dst);', end='\n', file=fc)
-        else:
-            if t in enum_types:
-                print('\tretval |= UA_'+t+'_encodeBinary(&(src->'+n+'),pos,dst);', end='\n', file=fc)
-            elif t.find("**") != -1:
-                print('\t//retval |= UA_Int32_encodeBinary(&(src->'+n+'Size),pos,dst); // encode size managed by UA_Array_encodeBinary', end='\n', file=fc)
-		print("\tretval |= UA_Array_encodeBinary((void const**) (src->"+n+"),src->"+n+"Size, UA_" + t[0:t.find("*")].upper()+",pos,dst);", end='\n', file=fc)
-            elif t.find("*") != -1:
-                print('\tretval |= UA_' + t[0:t.find("*")] + "_encodeBinary(src->" + n + ',pos,dst);', end='\n', file=fc)
-            else:
-                print('\tretval |= UA_'+t+"_encodeBinary(&(src->"+n+"),pos,dst);", end='\n', file=fc)
+		if t in elementary_size:
+			print('\tretval |= UA_'+t+'_encodeBinary(&(src->'+n+'),pos,dst);', end='\n', file=fc)
+		else:
+			if t in enum_types:
+				print('\tretval |= UA_'+t+'_encodeBinary(&(src->'+n+'),pos,dst);', end='\n', file=fc)
+			elif t.find("**") != -1:
+				print('\t//retval |= UA_Int32_encodeBinary(&(src->'+n+'Size),pos,dst); // encode size managed by UA_Array_encodeBinary', end='\n', file=fc)
+				print("\tretval |= UA_Array_encodeBinary((void const**) (src->"+n+"),src->"+n+"Size, UA_" + t[0:t.find("*")].upper()+",pos,dst);", end='\n', file=fc)
+			elif t.find("*") != -1:
+				print('\tretval |= UA_' + t[0:t.find("*")] + "_encodeBinary(src->" + n + ',pos,dst);', end='\n', file=fc)
+			else:
+				print('\tretval |= UA_'+t+"_encodeBinary(&(src->"+n+"),pos,dst);", end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
 
-    # code _decode
+	# code _decodeBinary
     print("UA_Int32 "+name+"_decodeBinary(UA_ByteString const * src, UA_Int32* pos, " + name + "* dst) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     print('\t'+name+'_init(dst);', end='\n', file=fc)
     for n,t in valuemap.iteritems():
@@ -191,10 +173,13 @@ def createStructured(element):
                 print('\tCHECKED_DECODE(UA_'+t+'_decodeBinary(src,pos,&(dst->'+n+')), '+name+'_deleteMembers(dst));', end='\n', file=fc)
             elif t.find("**") != -1:
             	# decode size
-		print('\tCHECKED_DECODE(UA_Int32_decodeBinary(src,pos,&(dst->'+n+'Size)), '+name+'_deleteMembers(dst)); // decode size', end='\n', file=fc)
+		print('\tCHECKED_DECODE(UA_Int32_decodeBinary(src,pos,&(dst->'+n+'Size)), ' +
+                      name + '_deleteMembers(dst)); // decode size', end='\n', file=fc)
 		# allocate memory for array
-		print("\tCHECKED_DECODE(UA_Array_new((void***)&dst->"+n+", dst->"+n+"Size, UA_"+t[0:t.find("*")].upper()+"), dst->"+n+" = UA_NULL; "+name+'_deleteMembers(dst));', end='\n', file=fc)
-		print("\tCHECKED_DECODE(UA_Array_decodeBinary(src,dst->"+n+"Size, UA_" + t[0:t.find("*")].upper()+",pos,(void *** const) (&dst->"+n+")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
+		print("\tCHECKED_DECODE(UA_Array_new((void***)&dst->"+n+", dst->"+n+"Size, UA_"+t[0:t.find("*")].upper()+"), dst->" +
+                      n + " = UA_NULL; "+name+'_deleteMembers(dst));', end='\n', file=fc)
+		print("\tCHECKED_DECODE(UA_Array_decodeBinary(src,dst->"+n+"Size, UA_" + t[0:t.find("*")].upper() +
+                      ",pos,(void *** const) (&dst->"+n+")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
             elif t.find("*") != -1:
 		#allocate memory using new
 		print('\tCHECKED_DECODE(UA_'+ t[0:t.find("*")] +"_new(&(dst->" + n + ")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
@@ -202,6 +187,12 @@ def createStructured(element):
             else:
                 print('\tCHECKED_DECODE(UA_'+t+"_decodeBinary(src,pos,&(dst->"+n+")), "+name+'_deleteMembers(dst));', end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
+ 
+    if not name in exclude_xml_decode:
+        print("UA_Int32 "+name+"_decodeXML(XML_Stack* s, XML_Attr* attr, " + name + "* dst, _Bool isStart)", end='\n', file=fc)
+        print('''{
+        DBG_VERBOSE(printf("'''+name+'''_decodeXML entered with dst=%p,isStart=%d\\n", (void* ) dst, isStart));
+        return UA_ERR_NOT_IMPLEMENTED;}''', end='\n', file=fc)
     
     # code _delete and _deleteMembers
     print('UA_Int32 '+name+'_delete('+name+'''* p) {
@@ -209,13 +200,13 @@ def createStructured(element):
 	retval |= '''+name+'''_deleteMembers(p);
 	retval |= UA_free(p);
 	return retval;
-    }''', end='\n', file=fc)
-    
+}''', end='\n', file=fc)
+	
     print("UA_Int32 "+name+"_deleteMembers(" + name + "* p) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     for n,t in valuemap.iteritems():
         if t not in elementary_size:
             if t.find("**") != -1:
-		print("\tretval |= UA_Array_delete((void***)&p->"+n+",p->"+n+"Size,UA_"+t[0:t.find("*")].upper()+"); p->"+n+" = UA_NULL;", end='\n', file=fc) #not tested
+		print("\tretval |= UA_Array_delete((void***)&p->"+n+",p->"+n+"Size,UA_"+t[0:t.find("*")].upper()+"); p->"+n+" = UA_NULL;", end='\n', file=fc)
             elif t.find("*") != -1:
 		print('\tretval |= UA_' + t[0:t.find("*")] + "_delete(p->"+n+");", end='\n', file=fc)
             else:
@@ -223,26 +214,26 @@ def createStructured(element):
 		
     print("\treturn retval;\n}\n", end='\n', file=fc)
 
-    # code _init
+	# code _init
     print("UA_Int32 "+name+"_init(" + name + " * p) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     for n,t in valuemap.iteritems():
-        if t in elementary_size:
-            print('\tretval |= UA_'+t+'_init(&(p->'+n+'));', end='\n', file=fc)
-        else:
-            if t in enum_types:
-                print('\tretval |= UA_'+t+'_init(&(p->'+n+'));', end='\n', file=fc)
-            elif t.find("**") != -1:
+		if t in elementary_size:
+			print('\tretval |= UA_'+t+'_init(&(p->'+n+'));', end='\n', file=fc)
+		else:
+			if t in enum_types:
+				print('\tretval |= UA_'+t+'_init(&(p->'+n+'));', end='\n', file=fc)
+			elif t.find("**") != -1:
 				print('\tp->'+n+'Size=0;', end='\n', file=fc)
 				print("\tp->"+n+"=UA_NULL;", end='\n', file=fc)
-            elif t.find("*") != -1:
+			elif t.find("*") != -1:
 				print("\tp->"+n+"=UA_NULL;", end='\n', file=fc)
-            else:
-                print('\tretval |= UA_'+t+"_init(&(p->"+n+"));", end='\n', file=fc)
+			else:
+				print('\tretval |= UA_'+t+"_init(&(p->"+n+"));", end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
 
-    # code _new
+	# code _new
     print("UA_TYPE_METHOD_NEW_DEFAULT(" + name + ")", end='\n', file=fc)
-    # code _copy
+	# code _copy
     print("UA_Int32 "+name+"_copy(" + name + " * src," + name + " * dst) {\n\tUA_Int32 retval = UA_SUCCESS;", end='\n', file=fc)
     for n,t in valuemap.iteritems():
         if t in elementary_size:
@@ -252,16 +243,17 @@ def createStructured(element):
                 print('\tretval |= UA_'+t+'_copy(&(src->'+n+'),&(dst->'+n+'));', end='\n', file=fc)
             elif t.find("**") != -1:
                 print('\tretval |= UA_Int32_copy(&(src->'+n+'Size),&(dst->'+n+'Size)); // size of following array', end='\n', file=fc)
-		print("\tretval |= UA_Array_copy((void const* const*) (src->"+n+"), src->"+n+"Size," + "UA_"+t[0:t.find("*")].upper()+",(void***)&(dst->"+n+"));", end='\n', file=fc)
+		print("\tretval |= UA_Array_copy((void const* const*) (src->"+n+"), src->"+n+"Size," + "UA_" +
+                      t[0:t.find("*")].upper()+",(void***)&(dst->"+n+"));", end='\n', file=fc)
             elif t.find("*") != -1:
                 print('\tretval |= UA_' + t[0:t.find("*")] + '_copy(src->' + n + ',dst->' + n + ');', end='\n', file=fc)
             else:
                 print('\tretval |= UA_'+t+"_copy(&(src->"+n+"),&(dst->" + n + '));', end='\n', file=fc)
     print("\treturn retval;\n}\n", end='\n', file=fc)
-    
+	
 def createOpaque(element):
     name = "UA_" + element.get("Name")
-    print("\n/** @name UA_" + name + " */", end='\n', file=fh)
+    print("\n/** @name " + name + " */\n", file=fh)
     for child in element:
         if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
             print("/** @brief " + child.text + " */", end='\n', file=fh)
@@ -271,26 +263,43 @@ def createOpaque(element):
     print("UA_TYPE_METHOD_CALCSIZE_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_ENCODEBINARY_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_DECODEBINARY_AS("+name+", UA_ByteString)", end='\n', file=fc)
+    print("UA_TYPE_METHOD_DECODEXML_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_DELETE_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_DELETEMEMBERS_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_INIT_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_COPY_AS("+name+", UA_ByteString)", end='\n', file=fc)
     print("UA_TYPE_METHOD_NEW_DEFAULT("+name+")\n", end='\n', file=fc)
 
-    return
-
 ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
 tree = etree.parse(sys.argv[1])
 types = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
 
 fh = open(sys.argv[2] + ".hgen",'w');
 fc = open(sys.argv[2] + ".cgen",'w');
-print('''/**********************************************************
- * '''+sys.argv[2]+'''.cgen -- do not modify
- **********************************************************
+
+print('''/**
+ * @file '''+sys.argv[2]+'''.h
+ *
+ * @brief Autogenerated data types defined in the UA standard
+ *
+ * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
+ * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
+ */
+
+#ifndef OPCUA_H_
+#define OPCUA_H_
+
+#include "ua_basictypes.h"
+#include "ua_namespace_0.h"''', end='\n', file=fh);
+
+print('''/**
+ * @file '''+sys.argv[2]+'''.c
+ *
+ * @brief Autogenerated function implementations to manage the data types defined in the UA standard
+ *
  * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
  * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
- **********************************************************/
+ */
  
 #include "''' + sys.argv[2] + '.h"', end='\n', file=fc);
 
@@ -298,24 +307,11 @@ print('''/**********************************************************
 arraytypes = set()
 fields = tree.xpath("//opc:Field", namespaces=ns)
 for field in fields:
-    if field.get("LengthField"):
-        arraytypes.add(stripTypename(field.get("TypeName")))
+	if field.get("LengthField"):
+		arraytypes.add(stripTypename(field.get("TypeName")))
 
 deferred_types = OrderedDict()
 
-print('''/**********************************************************
- * '''+sys.argv[2]+'''.hgen -- do not modify
- **********************************************************
- * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
- * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
- **********************************************************/
-
-#ifndef OPCUA_H_
-#define OPCUA_H_
-
-#include "ua_basictypes.h"
-#include "ua_namespace_0.h"''', end='\n', file=fh);
-
 #plugin handling
 import os
 files = [f for f in os.listdir('.') if os.path.isfile(f) and f[-3:] == ".py" and f[:7] == "plugin_"]
@@ -333,24 +329,24 @@ for f in files:
 #end plugin handling
 
 for element in types:
-    name = element.get("Name")
-    if skipType(name):
-        continue
-        
-    if element.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
-        createEnumerated(element)
-        printed_types.add(name)
-    elif element.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
-        if printableStructuredType(element):
-            createStructured(element)
-            structured_types.append(name)
-            printed_types.add(name)
-        else: # the record contains types that were not yet detailed
-            deferred_types[name] = element
-            continue
-    elif element.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
-        createOpaque(element)
-        printed_types.add(name)
+	name = element.get("Name")
+	if skipType(name):
+		continue
+		
+	if element.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
+		createEnumerated(element)
+		printed_types.add(name)
+	elif element.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
+		if printableStructuredType(element):
+			createStructured(element)
+			structured_types.append(name)
+			printed_types.add(name)
+		else: # the record contains types that were not yet detailed
+			deferred_types[name] = element
+			continue
+	elif element.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
+		createOpaque(element)
+		printed_types.add(name)
 
 for name, element in deferred_types.iteritems():
 	if name in plugin_types:
@@ -364,4 +360,3 @@ for name, element in deferred_types.iteritems():
 print('#endif /* OPCUA_H_ */', end='\n', file=fh)
 fh.close()
 fc.close()
-

+ 71 - 62
tools/generate_namespace.py

@@ -2,20 +2,15 @@ from __future__ import print_function
 import sys
 import platform
 import getpass
-from collections import OrderedDict
 import time
-import re
-import csv
-from itertools import tee
 
 if len(sys.argv) != 3:
-    print("Usage: python generate_namespace.py <path/to/NodeIds.csv> <outfile w/o extension>", file=sys.stdout)
-    exit(0)
+	print("Usage: python generate_namespace.py <path/to/NodeIds.csv> <outfile w/o extension>", file=sys.stdout)
+	exit(0)
 
 # types that are to be excluded
-exclude_kind = set(["Object","ObjectType","Variable","Method","ReferenceType"])
-exclude_types = set(["Number", 
-    "Integer", "UInteger", "Enumeration",
+exclude_kinds = set(["Object","ObjectType","Variable","Method","ReferenceType"])
+exclude_types = set(["Number", "Integer", "UInteger", "Enumeration",
 	"Image", "ImageBMP", "ImageGIF", "ImageJPG", "ImagePNG",
 	"References", "BaseVariableType", "BaseDataVariableType", 
 	"PropertyType", "DataTypeDescriptionType", "DataTypeDictionaryType", "NamingRuleType",
@@ -31,24 +26,16 @@ exclude_types = set(["Number",
 	"MultiStateDiscreteType", "ProgramDiagnosticType", "StateVariableType", "FiniteStateVariableType",
 	"TransitionVariableType", "FiniteTransitionVariableType", "BuildInfoType", "TwoStateVariableType",
 	"ConditionVariableType", "MultiStateValueDiscreteType", "OptionSetType", "ArrayItemType",
-	"YArrayItemType", "XYArrayItemType", "ImageItemType", "CubeItemType", "NDimensionArrayItemType"
-	])
-	
-def skipKind(name):
-    if name in exclude_kind:
-        return True
-    return False
-    
-def skipType(name):
-    if name in exclude_types:
-        return True
-    return False
+	"YArrayItemType", "XYArrayItemType", "ImageItemType", "CubeItemType", "NDimensionArrayItemType"])
 
 f = open(sys.argv[1])
-rows1, rows2, rows3 = tee(csv.reader(f), 3)
+input_str = f.read() + "\nInvalidType,0,DataType"
+input_str = input_str.replace('\r','')
+rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
+f.close()
 
-fh = open(sys.argv[2] + ".hgen",'w');
-fc = open(sys.argv[2] + ".cgen",'w');
+fh = open(sys.argv[2] + ".hgen",'w')
+fc = open(sys.argv[2] + ".cgen",'w')
 
 print('''/**********************************************************
  * '''+sys.argv[2]+'''.hgen -- do not modify
@@ -60,11 +47,27 @@ print('''/**********************************************************
 #ifndef OPCUA_NAMESPACE_0_H_
 #define OPCUA_NAMESPACE_0_H_
 
-#include "opcua.h"  // definition of UA_VTable and basic UA_Types
+#include "ua_basictypes.h"  // definition of UA_VTable and basic UA_Types
 
+/**
+ * @brief maps namespace zero nodeId to index into UA_VTable
+ *
+ * @param[in] ns0Id The namespace zero nodeId
+ *
+ * @retval UA_ERR_INVALID_VALUE whenever ns0Id could not be mapped
+ * @retval the corresponding index into UA_VTable
+ */
 UA_Int32 UA_ns0ToVTableIndex(UA_Int32 id);
 extern UA_VTable UA_[]; 
 
+static UA_Int32 phantom_delete(void * p) { return UA_SUCCESS; }
+extern UA_VTable UA_noDelete_[];
+
+/**
+ * @brief the set of possible indices into UA_VTable
+ *
+ * Enumerated type to define the types that the open62541 stack can handle
+ */
 enum UA_VTableIndex_enum {''', end='\n', file=fh)
 
 print('''/**********************************************************
@@ -76,49 +79,41 @@ print('''/**********************************************************
  
 #include "opcua.h"
 
-UA_Int32 UA_ns0ToVTableIndex(UA_Int32 id) {
-    UA_Int32 retval = UA_ERR_INVALID_VALUE;
-    switch (id) { ''', end='\n',file=fc)
+UA_Int32 UA_ns0ToVTableIndex(UA_Int32 ns0Id) {
+	UA_Int32 retval = UA_ERR_INVALID_VALUE;
+	switch (ns0Id) { ''', end='\n',file=fc)
 
 i = 0
-for row in rows1:
-    if skipKind(row[2]):
-	continue
-
-    if skipType(row[0]):
-	continue
-	
+for row in rows:
+    if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
+        continue
     if row[0] == "BaseDataType":
     	name = "UA_Variant"
     elif row[0] == "Structure":
-    	name = "UA_ExtensionObject" 
-    else:	
-	name = "UA_" + row[0]
+        name = "UA_ExtensionObject"
+    else:
+        name = "UA_" + row[0]
 	
-    print("\t"+name.upper()+"="+str(i)+",", file=fh)
+    print("\t"+name.upper()+" = "+str(i)+",", file=fh)
     print('\tcase '+row[1]+': retval='+name.upper()+'; break; //'+row[2], file=fc)
     i = i+1
 
-print('\tUA_INVALIDTYPE = '+str(i)+'\n};\n', file=fh)
-print('''\tcase 0: retval=UA_INVALIDTYPE; break;
+print("};\n", file=fh)
+print('''
     }
     return retval;
 }
 
 UA_VTable UA_[] = {''', file=fc)
 
-for row in rows2:
-    if skipKind(row[2]):
-	continue
-
-    if skipType(row[0]):
-	continue
-
+for row in rows:
+    if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
+        continue
     if row[0] == "BaseDataType":
-    	name = "UA_Variant"
+        name = "UA_Variant"
     elif row[0] == "Structure":
-    	name = "UA_ExtensionObject" 
-    else:	
+        name = "UA_ExtensionObject"
+    else:
 	name = "UA_" + row[0]
 
     print('#define '+name.upper()+'_NS0 '+row[1], file=fh)
@@ -127,26 +122,40 @@ for row in rows2:
           ",(UA_Int32(*)(void const*))"+name+"_calcSize" + 
           ",(UA_Int32(*)(UA_ByteString const*,UA_Int32*,void*))"+name+ "_decodeBinary" +
           ",(UA_Int32(*)(void const*,UA_Int32*,UA_ByteString*))"+name+"_encodeBinary"+
+          ",(UA_Int32(*)(XML_Stack*,XML_Attr*,void*,_Bool))"+ name + "_decodeXML" +
           ",(UA_Int32(*)(void *))"+name+"_init"+
           ",(UA_Int32(*)(void **))"+name+"_new"+
-	  ",(UA_Int32(*)(void const * ,void*))"+name+"_copy"+
+          ",(UA_Int32(*)(void const * ,void*))"+name+"_copy"+
           ",(UA_Int32(*)(void *))"+name+"_delete"+
+          (",sizeof("+name+")" if (name != "UA_InvalidType") else ",0") +
           ',(UA_Byte*)"'+name+'"},',end='\n',file=fc) 
-name = "UA_InvalidType"
-print("\t{0" + 
+
+print("};\n\nUA_VTable UA_noDelete_[] = {", end='\n', file=fc)
+
+for row in rows:
+    if row[0] == "" or row[0] in exclude_types or row[2] in exclude_kinds:
+        continue
+    if row[0] == "BaseDataType":
+        name = "UA_Variant"
+    elif row[0] == "Structure":
+        name = "UA_ExtensionObject"
+    else:	
+	name = "UA_" + row[0]
+
+    print("\t{" + row[1] +
           ",(UA_Int32(*)(void const*))"+name+"_calcSize" + 
           ",(UA_Int32(*)(UA_ByteString const*,UA_Int32*,void*))"+name+ "_decodeBinary" +
           ",(UA_Int32(*)(void const*,UA_Int32*,UA_ByteString*))"+name+"_encodeBinary"+
+          ",(UA_Int32(*)(XML_Stack*,XML_Attr*,void*,_Bool))" + name + "_decodeXML" +          
           ",(UA_Int32(*)(void *))"+name+"_init"+
           ",(UA_Int32(*)(void **))"+name+"_new"+
-	  ",(UA_Int32(*)(void const *, void *))"+name+"_copy"+
-          ",(UA_Int32(*)(void *))"+name+"_delete"+
-          ',(UA_Byte*)"'+name+'"}',end='\n',file=fc)
+          ",(UA_Int32(*)(void const * ,void*))"+name+"_copy"+
+          ",(UA_Int32(*)(void *))phantom_delete"+
+          (",sizeof("+name+")" if (name != "UA_InvalidType") else ",0") +
+          ',(UA_Byte*)"'+name+'"},',end='\n',file=fc)
 print("};", end='\n', file=fc) 
-print('#define '+name.upper()+'_NS0 0', file=fh)
-print('#endif /* OPCUA_NAMESPACE_0_H_ */', end='\n', file=fh)
+
+print('\n#endif /* OPCUA_NAMESPACE_0_H_ */', end='\n', file=fh)
+
 fh.close()
 fc.close()
-f.close()
-
-2222

+ 1 - 2
tools/indent.sh

@@ -12,7 +12,7 @@ fi
 # E.g. when indenting to the opening braces of an argument list.
 
 indent \
---line-length160 \
+--line-length120 \
 --comment-line-length100 \
 --indent-level4 \
 --use-tabs \
@@ -43,7 +43,6 @@ indent \
 --declaration-comment-column0 \
 --format-all-comments \
 --line-comments-indentation0 \
---blank-lines-before-block-comments \
 --space-special-semicolon \
 $@