Explorar el Código

Merge branch 'master' into inline_setattribute

Conflicts:
	examples/server.c
	include/ua_server.h
	src/server/ua_server_addressspace.c
	src/server/ua_services_attribute.c
	tests/check_services_attributes.c
Julius Pfrommer hace 9 años
padre
commit
29bed5ef22
Se han modificado 43 ficheros con 1799 adiciones y 3664 borrados
  1. 1 7
      CMakeLists.txt
  2. 0 39
      bindings/CMakeLists.txt
  3. 0 64
      bindings/open62541.i
  4. 822 0
      deps/tweetnacl.c
  5. 278 0
      deps/tweetnacl.h
  6. 122 9
      doc/building.rst
  7. 82 83
      examples/networklayer_tcp.c
  8. 4 2
      examples/networklayer_tcp.h
  9. 92 95
      examples/networklayer_udp.c
  10. 6 6
      examples/networklayer_udp.h
  11. 9 8
      examples/server_udp.c
  12. 11 0
      examples/server_variable.c
  13. 1 1
      include/ua_client.h
  14. 31 26
      include/ua_connection.h
  15. 56 0
      include/ua_job.h
  16. 28 39
      include/ua_server.h
  17. 0 51
      ports/WAGO-750-860.patch
  18. 17 18
      src/client/ua_client.c
  19. 0 281
      src/ongoing/generateSam.c
  20. 0 85
      src/ongoing/ua_namespace_xml.c
  21. 0 41
      src/ongoing/ua_namespace_xml.h
  22. 0 447
      src/ongoing/ua_types_encoding_xml.c
  23. 0 77
      src/ongoing/ua_types_encoding_xml.h
  24. 0 980
      src/ongoing/ua_xml.c
  25. 0 134
      src/ongoing/ua_xml.h
  26. 0 210
      src/ongoing/xml2ns0.c
  27. 14 10
      src/server/ua_nodes.c
  28. 8 2
      src/server/ua_nodes.h
  29. 68 78
      src/server/ua_server.c
  30. 0 755
      src/server/ua_server_addressspace.c
  31. 22 29
      src/server/ua_server_binary.c
  32. 1 1
      src/server/ua_server_internal.h
  33. 17 8
      src/server/ua_server_worker.c
  34. 18 12
      src/server/ua_services_attribute.c
  35. 10 10
      src/server/ua_services_call.c
  36. 1 1
      src/server/ua_services_nodemanagement.c
  37. 6 3
      src/server/ua_subscription.c
  38. 61 40
      src/ua_connection.c
  39. 6 6
      src/ua_securechannel.c
  40. 1 0
      src/ua_types.c
  41. 1 1
      tests/check_services_attributes.c
  42. 3 3
      tools/pyUANamespace/ua_builtin_types.py
  43. 2 2
      tools/pyUANamespace/ua_node_types.py

+ 1 - 7
CMakeLists.txt

@@ -82,6 +82,7 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_types.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_job.h
                      ${PROJECT_SOURCE_DIR}/include/ua_connection.h
                      ${PROJECT_SOURCE_DIR}/include/ua_log.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server.h
@@ -295,13 +296,6 @@ if(ENABLE_MULTITHREADING)
   target_link_libraries(open62541-static urcu-cds urcu urcu-common pthread)
 endif()
 
-# build language bindings for the library
-option(ENABLE_BINDING_LUA "Build Lua bindings" OFF)
-option(ENABLE_BINDING_PYTHON "Build Python bindings" OFF)
-if(ENABLE_BINDING_LUA OR ENABLE_BINDING_PYTHON)
-    add_subdirectory(bindings)
-endif()
-
 # coverage
 option(ENABLE_COVERAGE "Enable gcov coverage" OFF)
 if(ENABLE_COVERAGE)

+ 0 - 39
bindings/CMakeLists.txt

@@ -1,39 +0,0 @@
-FIND_PACKAGE(SWIG REQUIRED)
-INCLUDE(UseSWIG)
-
-if(ENABLE_BINDING_LUA)
-    FIND_PACKAGE(Lua51)
-    file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/lua)
-    add_custom_command (OUTPUT ${PROJECT_BINARY_DIR}/lua/lua_wrap.c 
-                        COMMAND ${SWIG_EXECUTABLE} -lua
-                        -I${PROJECT_SOURCE_DIR}/include
-                        -o ${PROJECT_BINARY_DIR}/lua/lua_wrap.c
-                        ${PROJECT_SOURCE_DIR}/bindings/open62541.i
-                        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/open62541.i)
-    add_library(open62541-lua SHARED ${PROJECT_BINARY_DIR}/lua/lua_wrap.c)
-    set_target_properties(open62541-lua PROPERTIES COMPILE_FLAGS "-Wno-error")
-    target_include_directories(open62541-lua PUBLIC ${LUA_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/include
-                                                    ${PROJECT_BINARY_DIR}/src_generated)
-    target_link_libraries(open62541-lua open62541 lua)
-    set_target_properties(open62541-lua PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lua
-                                                   OUTPUT_NAME open62541 PREFIX "")
-endif()
-
-if(ENABLE_BINDING_PYTHON)
-    FIND_PACKAGE(PythonLibs)
-    file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/python)
-    add_custom_command (OUTPUT ${PROJECT_BINARY_DIR}/python/python_wrap.c 
-                        COMMAND ${SWIG_EXECUTABLE} -python
-                        -I${PROJECT_SOURCE_DIR}/include
-                        -o ${PROJECT_BINARY_DIR}/python/python_wrap.c
-                        ${PROJECT_SOURCE_DIR}/bindings/open62541.i
-                        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/open62541.i)
-    add_library(open62541-python SHARED ${PROJECT_BINARY_DIR}/python/python_wrap.c)
-    set_target_properties(open62541-python PROPERTIES COMPILE_FLAGS "-Wno-error")
-    target_include_directories(open62541-python PUBLIC ${PYTHON_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/include
-                                                       ${PROJECT_BINARY_DIR}/src_generated)
-    target_link_libraries(open62541-python open62541 python)
-    set_target_properties(open62541-python PROPERTIES
-                                           LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/python
-                                           OUTPUT_NAME _open62541 PREFIX "")
-endif()

+ 0 - 64
bindings/open62541.i

@@ -1,64 +0,0 @@
-%module open62541
-%{
-#include "ua_types.h"
-#include "ua_server.h"
-%}
-
-#if defined(SWIGPYTHON)
-%{
-/* avoid no previous prototype warning/error */
-#if PY_VERSION_HEX >= 0x03000000
-PyObject*
-#else
-void
-#endif
-SWIG_init (void);
-%}
-#endif
-
-#if defined(SWIGLUA)
-%{
-/* avoid no previous prototype warning/error */
-SWIGEXPORT int SWIG_init (lua_State* L);
-%}
-#endif
-
-%define UA_TYPE_HANDLING_FUNCTIONS_SWIG(TYPE)
-    TYPE * TYPE##_new(void);
-    void TYPE##_init(TYPE * p);
-    void TYPE##_delete(TYPE * p);
-    void TYPE##_deleteMembers(TYPE * p);
-    UA_StatusCode TYPE##_copy(const TYPE *src, TYPE *dst);
-%enddef
-
-%define UA_EXPORT
-%enddef
-
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Boolean)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_SByte)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Byte)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Int16)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_UInt16)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Int32)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_UInt32)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Int64)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_UInt64)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Float)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Double)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_String)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_DateTime)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Guid)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_ByteString)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_XmlElement)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_NodeId)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_ExpandedNodeId)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_StatusCode)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_QualifiedName)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_LocalizedText)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_ExtensionObject)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_DataValue)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Variant)
-UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_DiagnosticInfo)
-
-%include "ua_types.h"
-%include "ua_server.h"

+ 822 - 0
deps/tweetnacl.c

@@ -0,0 +1,822 @@
+ /*
+  * http://tweetnacl.cr.yp.to/
+  * TweetNaCl was put in the public domain by the authors Bernstein et al.
+  * The API is th same as for NaCl (http://nacl.cr.yp.to/).
+  */
+
+#include "tweetnacl.h"
+#define FOR(i,n) for (i = 0;i < n;++i)
+#define sv static void
+
+/* Manual change from TweetNaCl version 20140427: Use C99 integer types
+typedef unsigned char u8;
+typedef unsigned long u32;
+typedef unsigned long long u64;
+typedef long long i64; */
+#include <inttypes.h>
+typedef uint8_t u8;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef int64_t i64;
+/* end manual change */
+typedef i64 gf[16];
+extern void randombytes(u8 *,u64);
+
+static const u8
+  _0[16],
+  _9[32] = {9};
+static const gf
+  gf0,
+  gf1 = {1},
+  _121665 = {0xDB41,1},
+  D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203},
+  D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406},
+  X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169},
+  Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666},
+  I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83};
+
+static u32 L32(u32 x,int c) { return (x << c) | ((x&0xffffffff) >> (32 - c)); }
+
+static u32 ld32(const u8 *x)
+{
+  u32 u = x[3];
+  u = (u<<8)|x[2];
+  u = (u<<8)|x[1];
+  return (u<<8)|x[0];
+}
+
+static u64 dl64(const u8 *x)
+{
+  u64 i,u=0;
+  FOR(i,8) u=(u<<8)|x[i];
+  return u;
+}
+
+sv st32(u8 *x,u32 u)
+{
+  int i;
+  FOR(i,4) { x[i] = u; u >>= 8; }
+}
+
+sv ts64(u8 *x,u64 u)
+{
+  int i;
+  for (i = 7;i >= 0;--i) { x[i] = u; u >>= 8; }
+}
+
+static int vn(const u8 *x,const u8 *y,int n)
+{
+  u32 i,d = 0;
+  FOR(i,n) d |= x[i]^y[i];
+  return (1 & ((d - 1) >> 8)) - 1;
+}
+
+int crypto_verify_16(const u8 *x,const u8 *y)
+{
+  return vn(x,y,16);
+}
+
+int crypto_verify_32(const u8 *x,const u8 *y)
+{
+  return vn(x,y,32);
+}
+
+sv core(u8 *out,const u8 *in,const u8 *k,const u8 *c,int h)
+{
+  u32 w[16],x[16],y[16],t[4];
+  int i,j,m;
+
+  FOR(i,4) {
+    x[5*i] = ld32(c+4*i);
+    x[1+i] = ld32(k+4*i);
+    x[6+i] = ld32(in+4*i);
+    x[11+i] = ld32(k+16+4*i);
+  }
+
+  FOR(i,16) y[i] = x[i];
+
+  FOR(i,20) {
+    FOR(j,4) {
+      FOR(m,4) t[m] = x[(5*j+4*m)%16];
+      t[1] ^= L32(t[0]+t[3], 7);
+      t[2] ^= L32(t[1]+t[0], 9);
+      t[3] ^= L32(t[2]+t[1],13);
+      t[0] ^= L32(t[3]+t[2],18);
+      FOR(m,4) w[4*j+(j+m)%4] = t[m];
+    }
+    FOR(m,16) x[m] = w[m];
+  }
+
+  if (h) {
+    FOR(i,16) x[i] += y[i];
+    FOR(i,4) {
+      x[5*i] -= ld32(c+4*i);
+      x[6+i] -= ld32(in+4*i);
+    }
+    FOR(i,4) {
+      st32(out+4*i,x[5*i]);
+      st32(out+16+4*i,x[6+i]);
+    }
+  } else
+    FOR(i,16) st32(out + 4 * i,x[i] + y[i]);
+}
+
+int crypto_core_salsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c)
+{
+  core(out,in,k,c,0);
+  return 0;
+}
+
+int crypto_core_hsalsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c)
+{
+  core(out,in,k,c,1);
+  return 0;
+}
+
+static const u8 sigma[16] = "expand 32-byte k";
+
+int crypto_stream_salsa20_xor(u8 *c,const u8 *m,u64 b,const u8 *n,const u8 *k)
+{
+  u8 z[16],x[64];
+  u32 u,i;
+  if (!b) return 0;
+  FOR(i,16) z[i] = 0;
+  FOR(i,8) z[i] = n[i];
+  while (b >= 64) {
+    crypto_core_salsa20(x,z,k,sigma);
+    FOR(i,64) c[i] = (m?m[i]:0) ^ x[i];
+    u = 1;
+    for (i = 8;i < 16;++i) {
+      u += (u32) z[i];
+      z[i] = u;
+      u >>= 8;
+    }
+    b -= 64;
+    c += 64;
+    if (m) m += 64;
+  }
+  if (b) {
+    crypto_core_salsa20(x,z,k,sigma);
+    FOR(i,b) c[i] = (m?m[i]:0) ^ x[i];
+  }
+  return 0;
+}
+
+int crypto_stream_salsa20(u8 *c,u64 d,const u8 *n,const u8 *k)
+{
+  return crypto_stream_salsa20_xor(c,0,d,n,k);
+}
+
+int crypto_stream(u8 *c,u64 d,const u8 *n,const u8 *k)
+{
+  u8 s[32];
+  crypto_core_hsalsa20(s,n,k,sigma);
+  return crypto_stream_salsa20(c,d,n+16,s);
+}
+
+int crypto_stream_xor(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k)
+{
+  u8 s[32];
+  crypto_core_hsalsa20(s,n,k,sigma);
+  return crypto_stream_salsa20_xor(c,m,d,n+16,s);
+}
+
+sv add1305(u32 *h,const u32 *c)
+{
+  u32 j,u = 0;
+  FOR(j,17) {
+    u += h[j] + c[j];
+    h[j] = u & 255;
+    u >>= 8;
+  }
+}
+
+static const u32 minusp[17] = {
+  5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252
+} ;
+
+int crypto_onetimeauth(u8 *out,const u8 *m,u64 n,const u8 *k)
+{
+  u32 s,i,j,u,x[17],r[17],h[17],c[17],g[17];
+
+  FOR(j,17) r[j]=h[j]=0;
+  FOR(j,16) r[j]=k[j];
+  r[3]&=15;
+  r[4]&=252;
+  r[7]&=15;
+  r[8]&=252;
+  r[11]&=15;
+  r[12]&=252;
+  r[15]&=15;
+
+  while (n > 0) {
+    FOR(j,17) c[j] = 0;
+    for (j = 0;(j < 16) && (j < n);++j) c[j] = m[j];
+    c[j] = 1;
+    m += j; n -= j;
+    add1305(h,c);
+    FOR(i,17) {
+      x[i] = 0;
+      FOR(j,17) x[i] += h[j] * ((j <= i) ? r[i - j] : 320 * r[i + 17 - j]);
+    }
+    FOR(i,17) h[i] = x[i];
+    u = 0;
+    FOR(j,16) {
+      u += h[j];
+      h[j] = u & 255;
+      u >>= 8;
+    }
+    u += h[16]; h[16] = u & 3;
+    u = 5 * (u >> 2);
+    FOR(j,16) {
+      u += h[j];
+      h[j] = u & 255;
+      u >>= 8;
+    }
+    u += h[16]; h[16] = u;
+  }
+
+  FOR(j,17) g[j] = h[j];
+  add1305(h,minusp);
+  s = -(h[16] >> 7);
+  FOR(j,17) h[j] ^= s & (g[j] ^ h[j]);
+
+  FOR(j,16) c[j] = k[j + 16];
+  c[16] = 0;
+  add1305(h,c);
+  FOR(j,16) out[j] = h[j];
+  return 0;
+}
+
+int crypto_onetimeauth_verify(const u8 *h,const u8 *m,u64 n,const u8 *k)
+{
+  u8 x[16];
+  crypto_onetimeauth(x,m,n,k);
+  return crypto_verify_16(h,x);
+}
+
+int crypto_secretbox(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k)
+{
+  int i;
+  if (d < 32) return -1;
+  crypto_stream_xor(c,m,d,n,k);
+  crypto_onetimeauth(c + 16,c + 32,d - 32,c);
+  FOR(i,16) c[i] = 0;
+  return 0;
+}
+
+int crypto_secretbox_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k)
+{
+  int i;
+  u8 x[32];
+  if (d < 32) return -1;
+  crypto_stream(x,32,n,k);
+  if (crypto_onetimeauth_verify(c + 16,c + 32,d - 32,x) != 0) return -1;
+  crypto_stream_xor(m,c,d,n,k);
+  FOR(i,32) m[i] = 0;
+  return 0;
+}
+
+sv set25519(gf r, const gf a)
+{
+  int i;
+  FOR(i,16) r[i]=a[i];
+}
+
+sv car25519(gf o)
+{
+  int i;
+  i64 c;
+  FOR(i,16) {
+    o[i]+=(1LL<<16);
+    c=o[i]>>16;
+    o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15);
+    o[i]-=c<<16;
+  }
+}
+
+sv sel25519(gf p,gf q,int b)
+{
+  i64 t,i,c=~(b-1);
+  FOR(i,16) {
+    t= c&(p[i]^q[i]);
+    p[i]^=t;
+    q[i]^=t;
+  }
+}
+
+sv pack25519(u8 *o,const gf n)
+{
+  int i,j,b;
+  gf m,t;
+  FOR(i,16) t[i]=n[i];
+  car25519(t);
+  car25519(t);
+  car25519(t);
+  FOR(j,2) {
+    m[0]=t[0]-0xffed;
+    for(i=1;i<15;i++) {
+      m[i]=t[i]-0xffff-((m[i-1]>>16)&1);
+      m[i-1]&=0xffff;
+    }
+    m[15]=t[15]-0x7fff-((m[14]>>16)&1);
+    b=(m[15]>>16)&1;
+    m[14]&=0xffff;
+    sel25519(t,m,1-b);
+  }
+  FOR(i,16) {
+    o[2*i]=t[i]&0xff;
+    o[2*i+1]=t[i]>>8;
+  }
+}
+
+static int neq25519(const gf a, const gf b)
+{
+  u8 c[32],d[32];
+  pack25519(c,a);
+  pack25519(d,b);
+  return crypto_verify_32(c,d);
+}
+
+static u8 par25519(const gf a)
+{
+  u8 d[32];
+  pack25519(d,a);
+  return d[0]&1;
+}
+
+sv unpack25519(gf o, const u8 *n)
+{
+  int i;
+  FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8);
+  o[15]&=0x7fff;
+}
+
+sv A(gf o,const gf a,const gf b)
+{
+  int i;
+  FOR(i,16) o[i]=a[i]+b[i];
+}
+
+sv Z(gf o,const gf a,const gf b)
+{
+  int i;
+  FOR(i,16) o[i]=a[i]-b[i];
+}
+
+sv M(gf o,const gf a,const gf b)
+{
+  i64 i,j,t[31];
+  FOR(i,31) t[i]=0;
+  FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j];
+  FOR(i,15) t[i]+=38*t[i+16];
+  FOR(i,16) o[i]=t[i];
+  car25519(o);
+  car25519(o);
+}
+
+sv S(gf o,const gf a)
+{
+  M(o,a,a);
+}
+
+sv inv25519(gf o,const gf i)
+{
+  gf c;
+  int a;
+  FOR(a,16) c[a]=i[a];
+  for(a=253;a>=0;a--) {
+    S(c,c);
+    if(a!=2&&a!=4) M(c,c,i);
+  }
+  FOR(a,16) o[a]=c[a];
+}
+
+sv pow2523(gf o,const gf i)
+{
+  gf c;
+  int a;
+  FOR(a,16) c[a]=i[a];
+  for(a=250;a>=0;a--) {
+    S(c,c);
+    if(a!=1) M(c,c,i);
+  }
+  FOR(a,16) o[a]=c[a];
+}
+
+int crypto_scalarmult(u8 *q,const u8 *n,const u8 *p)
+{
+  u8 z[32];
+  i64 x[80],r,i;
+  gf a,b,c,d,e,f;
+  FOR(i,31) z[i]=n[i];
+  z[31]=(n[31]&127)|64;
+  z[0]&=248;
+  unpack25519(x,p);
+  FOR(i,16) {
+    b[i]=x[i];
+    d[i]=a[i]=c[i]=0;
+  }
+  a[0]=d[0]=1;
+  for(i=254;i>=0;--i) {
+    r=(z[i>>3]>>(i&7))&1;
+    sel25519(a,b,r);
+    sel25519(c,d,r);
+    A(e,a,c);
+    Z(a,a,c);
+    A(c,b,d);
+    Z(b,b,d);
+    S(d,e);
+    S(f,a);
+    M(a,c,a);
+    M(c,b,e);
+    A(e,a,c);
+    Z(a,a,c);
+    S(b,a);
+    Z(c,d,f);
+    M(a,c,_121665);
+    A(a,a,d);
+    M(c,c,a);
+    M(a,d,f);
+    M(d,b,x);
+    S(b,e);
+    sel25519(a,b,r);
+    sel25519(c,d,r);
+  }
+  FOR(i,16) {
+    x[i+16]=a[i];
+    x[i+32]=c[i];
+    x[i+48]=b[i];
+    x[i+64]=d[i];
+  }
+  inv25519(x+32,x+32);
+  M(x+16,x+16,x+32);
+  pack25519(q,x+16);
+  return 0;
+}
+
+int crypto_scalarmult_base(u8 *q,const u8 *n)
+{ 
+  return crypto_scalarmult(q,n,_9);
+}
+
+int crypto_box_keypair(u8 *y,u8 *x)
+{
+  randombytes(x,32);
+  return crypto_scalarmult_base(y,x);
+}
+
+int crypto_box_beforenm(u8 *k,const u8 *y,const u8 *x)
+{
+  u8 s[32];
+  crypto_scalarmult(s,x,y);
+  return crypto_core_hsalsa20(k,_0,s,sigma);
+}
+
+int crypto_box_afternm(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k)
+{
+  return crypto_secretbox(c,m,d,n,k);
+}
+
+int crypto_box_open_afternm(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k)
+{
+  return crypto_secretbox_open(m,c,d,n,k);
+}
+
+int crypto_box(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *y,const u8 *x)
+{
+  u8 k[32];
+  crypto_box_beforenm(k,y,x);
+  return crypto_box_afternm(c,m,d,n,k);
+}
+
+int crypto_box_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *y,const u8 *x)
+{
+  u8 k[32];
+  crypto_box_beforenm(k,y,x);
+  return crypto_box_open_afternm(m,c,d,n,k);
+}
+
+static u64 R(u64 x,int c) { return (x >> c) | (x << (64 - c)); }
+static u64 Ch(u64 x,u64 y,u64 z) { return (x & y) ^ (~x & z); }
+static u64 Maj(u64 x,u64 y,u64 z) { return (x & y) ^ (x & z) ^ (y & z); }
+static u64 Sigma0(u64 x) { return R(x,28) ^ R(x,34) ^ R(x,39); }
+static u64 Sigma1(u64 x) { return R(x,14) ^ R(x,18) ^ R(x,41); }
+static u64 sigma0(u64 x) { return R(x, 1) ^ R(x, 8) ^ (x >> 7); }
+static u64 sigma1(u64 x) { return R(x,19) ^ R(x,61) ^ (x >> 6); }
+
+static const u64 K[80] = 
+{
+  0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+  0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+  0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+  0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+  0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+  0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+  0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+  0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+  0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+  0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+  0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+  0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+  0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+  0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+  0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+  0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+  0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+  0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+  0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+  0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+int crypto_hashblocks(u8 *x,const u8 *m,u64 n)
+{
+  u64 z[8],b[8],a[8],w[16],t;
+  int i,j;
+
+  FOR(i,8) z[i] = a[i] = dl64(x + 8 * i);
+
+  while (n >= 128) {
+    FOR(i,16) w[i] = dl64(m + 8 * i);
+
+    FOR(i,80) {
+      FOR(j,8) b[j] = a[j];
+      t = a[7] + Sigma1(a[4]) + Ch(a[4],a[5],a[6]) + K[i] + w[i%16];
+      b[7] = t + Sigma0(a[0]) + Maj(a[0],a[1],a[2]);
+      b[3] += t;
+      FOR(j,8) a[(j+1)%8] = b[j];
+      if (i%16 == 15)
+	FOR(j,16)
+	  w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]);
+    }
+
+    FOR(i,8) { a[i] += z[i]; z[i] = a[i]; }
+
+    m += 128;
+    n -= 128;
+  }
+
+  FOR(i,8) ts64(x+8*i,z[i]);
+
+  return n;
+}
+
+static const u8 iv[64] = {
+  0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
+  0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
+  0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
+  0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1,
+  0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1,
+  0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f,
+  0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b,
+  0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
+} ;
+
+int crypto_hash(u8 *out,const u8 *m,u64 n)
+{
+  u8 h[64],x[256];
+  u64 i,b = n;
+
+  FOR(i,64) h[i] = iv[i];
+
+  crypto_hashblocks(h,m,n);
+  m += n;
+  n &= 127;
+  m -= n;
+
+  FOR(i,256) x[i] = 0;
+  FOR(i,n) x[i] = m[i];
+  x[n] = 128;
+
+  n = 256-128*(n<112);
+  x[n-9] = b >> 61;
+  ts64(x+n-8,b<<3);
+  crypto_hashblocks(h,x,n);
+
+  FOR(i,64) out[i] = h[i];
+
+  return 0;
+}
+
+sv add(gf p[4],gf q[4])
+{
+  gf a,b,c,d,t,e,f,g,h;
+  
+  Z(a, p[1], p[0]);
+  Z(t, q[1], q[0]);
+  M(a, a, t);
+  A(b, p[0], p[1]);
+  A(t, q[0], q[1]);
+  M(b, b, t);
+  M(c, p[3], q[3]);
+  M(c, c, D2);
+  M(d, p[2], q[2]);
+  A(d, d, d);
+  Z(e, b, a);
+  Z(f, d, c);
+  A(g, d, c);
+  A(h, b, a);
+
+  M(p[0], e, f);
+  M(p[1], h, g);
+  M(p[2], g, f);
+  M(p[3], e, h);
+}
+
+sv cswap(gf p[4],gf q[4],u8 b)
+{
+  int i;
+  FOR(i,4)
+    sel25519(p[i],q[i],b);
+}
+
+sv pack(u8 *r,gf p[4])
+{
+  gf tx, ty, zi;
+  inv25519(zi, p[2]); 
+  M(tx, p[0], zi);
+  M(ty, p[1], zi);
+  pack25519(r, ty);
+  r[31] ^= par25519(tx) << 7;
+}
+
+sv scalarmult(gf p[4],gf q[4],const u8 *s)
+{
+  int i;
+  set25519(p[0],gf0);
+  set25519(p[1],gf1);
+  set25519(p[2],gf1);
+  set25519(p[3],gf0);
+  for (i = 255;i >= 0;--i) {
+    u8 b = (s[i/8]>>(i&7))&1;
+    cswap(p,q,b);
+    add(q,p);
+    add(p,p);
+    cswap(p,q,b);
+  }
+}
+
+sv scalarbase(gf p[4],const u8 *s)
+{
+  gf q[4];
+  set25519(q[0],X);
+  set25519(q[1],Y);
+  set25519(q[2],gf1);
+  M(q[3],X,Y);
+  scalarmult(p,q,s);
+}
+
+int crypto_sign_keypair(u8 *pk, u8 *sk)
+{
+  u8 d[64];
+  gf p[4];
+  int i;
+
+  randombytes(sk, 32);
+  crypto_hash(d, sk, 32);
+  d[0] &= 248;
+  d[31] &= 127;
+  d[31] |= 64;
+
+  scalarbase(p,d);
+  pack(pk,p);
+
+  FOR(i,32) sk[32 + i] = pk[i];
+  return 0;
+}
+
+static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10};
+
+sv modL(u8 *r,i64 x[64])
+{
+  i64 carry,i,j;
+  for (i = 63;i >= 32;--i) {
+    carry = 0;
+    for (j = i - 32;j < i - 12;++j) {
+      x[j] += carry - 16 * x[i] * L[j - (i - 32)];
+      carry = (x[j] + 128) >> 8;
+      x[j] -= carry << 8;
+    }
+    x[j] += carry;
+    x[i] = 0;
+  }
+  carry = 0;
+  FOR(j,32) {
+    x[j] += carry - (x[31] >> 4) * L[j];
+    carry = x[j] >> 8;
+    x[j] &= 255;
+  }
+  FOR(j,32) x[j] -= carry * L[j];
+  FOR(i,32) {
+    x[i+1] += x[i] >> 8;
+    r[i] = x[i] & 255;
+  }
+}
+
+sv reduce(u8 *r)
+{
+  i64 x[64],i;
+  FOR(i,64) x[i] = (u64) r[i];
+  FOR(i,64) r[i] = 0;
+  modL(r,x);
+}
+
+int crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 n,const u8 *sk)
+{
+  u8 d[64],h[64],r[64];
+  i64 i,j,x[64];
+  gf p[4];
+
+  crypto_hash(d, sk, 32);
+  d[0] &= 248;
+  d[31] &= 127;
+  d[31] |= 64;
+
+  *smlen = n+64;
+  FOR(i,n) sm[64 + i] = m[i];
+  FOR(i,32) sm[32 + i] = d[32 + i];
+
+  crypto_hash(r, sm+32, n+32);
+  reduce(r);
+  scalarbase(p,r);
+  pack(sm,p);
+
+  FOR(i,32) sm[i+32] = sk[i+32];
+  crypto_hash(h,sm,n + 64);
+  reduce(h);
+
+  FOR(i,64) x[i] = 0;
+  FOR(i,32) x[i] = (u64) r[i];
+  FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j];
+  modL(sm + 32,x);
+
+  return 0;
+}
+
+static int unpackneg(gf r[4],const u8 p[32])
+{
+  gf t, chk, num, den, den2, den4, den6;
+  set25519(r[2],gf1);
+  unpack25519(r[1],p);
+  S(num,r[1]);
+  M(den,num,D);
+  Z(num,num,r[2]);
+  A(den,r[2],den);
+
+  S(den2,den);
+  S(den4,den2);
+  M(den6,den4,den2);
+  M(t,den6,num);
+  M(t,t,den);
+
+  pow2523(t,t);
+  M(t,t,num);
+  M(t,t,den);
+  M(t,t,den);
+  M(r[0],t,den);
+
+  S(chk,r[0]);
+  M(chk,chk,den);
+  if (neq25519(chk, num)) M(r[0],r[0],I);
+
+  S(chk,r[0]);
+  M(chk,chk,den);
+  if (neq25519(chk, num)) return -1;
+
+  if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]);
+
+  M(r[3],r[0],r[1]);
+  return 0;
+}
+
+int crypto_sign_open(u8 *m,u64 *mlen,const u8 *sm,u64 n,const u8 *pk)
+{
+  int i;
+  u8 t[32],h[64];
+  gf p[4],q[4];
+
+  *mlen = -1;
+  if (n < 64) return -1;
+
+  if (unpackneg(q,pk)) return -1;
+
+  FOR(i,n) m[i] = sm[i];
+  FOR(i,32) m[i+32] = pk[i];
+  crypto_hash(h,m,n);
+  reduce(h);
+  scalarmult(p,q,h);
+
+  scalarbase(q,sm + 32);
+  add(p,q);
+  pack(t,p);
+
+  n -= 64;
+  if (crypto_verify_32(sm, t)) {
+    FOR(i,n) m[i] = 0;
+    return -1;
+  }
+
+  FOR(i,n) m[i] = sm[i + 64];
+  *mlen = n;
+  return 0;
+}

+ 278 - 0
deps/tweetnacl.h

@@ -0,0 +1,278 @@
+ /*
+  * http://tweetnacl.cr.yp.to/
+  * TweetNaCl was put in the public domain by the authors Bernstein et al.
+  * The API is th same as for NaCl (http://nacl.cr.yp.to/).
+  */
+
+#ifndef TWEETNACL_H
+#define TWEETNACL_H
+#define crypto_auth_PRIMITIVE "hmacsha512256"
+#define crypto_auth crypto_auth_hmacsha512256
+#define crypto_auth_verify crypto_auth_hmacsha512256_verify
+#define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES
+#define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES
+#define crypto_auth_IMPLEMENTATION crypto_auth_hmacsha512256_IMPLEMENTATION
+#define crypto_auth_VERSION crypto_auth_hmacsha512256_VERSION
+#define crypto_auth_hmacsha512256_tweet_BYTES 32
+#define crypto_auth_hmacsha512256_tweet_KEYBYTES 32
+extern int crypto_auth_hmacsha512256_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
+extern int crypto_auth_hmacsha512256_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
+#define crypto_auth_hmacsha512256_tweet_VERSION "-"
+#define crypto_auth_hmacsha512256 crypto_auth_hmacsha512256_tweet
+#define crypto_auth_hmacsha512256_verify crypto_auth_hmacsha512256_tweet_verify
+#define crypto_auth_hmacsha512256_BYTES crypto_auth_hmacsha512256_tweet_BYTES
+#define crypto_auth_hmacsha512256_KEYBYTES crypto_auth_hmacsha512256_tweet_KEYBYTES
+#define crypto_auth_hmacsha512256_VERSION crypto_auth_hmacsha512256_tweet_VERSION
+#define crypto_auth_hmacsha512256_IMPLEMENTATION "crypto_auth/hmacsha512256/tweet"
+#define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305"
+#define crypto_box crypto_box_curve25519xsalsa20poly1305
+#define crypto_box_open crypto_box_curve25519xsalsa20poly1305_open
+#define crypto_box_keypair crypto_box_curve25519xsalsa20poly1305_keypair
+#define crypto_box_beforenm crypto_box_curve25519xsalsa20poly1305_beforenm
+#define crypto_box_afternm crypto_box_curve25519xsalsa20poly1305_afternm
+#define crypto_box_open_afternm crypto_box_curve25519xsalsa20poly1305_open_afternm
+#define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES
+#define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES
+#define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES
+#define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES
+#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
+#define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES
+#define crypto_box_IMPLEMENTATION crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION
+#define crypto_box_VERSION crypto_box_curve25519xsalsa20poly1305_VERSION
+#define crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES 32
+#define crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES 32
+#define crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES 32
+#define crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES 24
+#define crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES 32
+#define crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES 16
+extern int crypto_box_curve25519xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *);
+extern int crypto_box_curve25519xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *);
+extern int crypto_box_curve25519xsalsa20poly1305_tweet_keypair(unsigned char *,unsigned char *);
+extern int crypto_box_curve25519xsalsa20poly1305_tweet_beforenm(unsigned char *,const unsigned char *,const unsigned char *);
+extern int crypto_box_curve25519xsalsa20poly1305_tweet_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
+extern int crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
+#define crypto_box_curve25519xsalsa20poly1305_tweet_VERSION "-"
+#define crypto_box_curve25519xsalsa20poly1305 crypto_box_curve25519xsalsa20poly1305_tweet
+#define crypto_box_curve25519xsalsa20poly1305_open crypto_box_curve25519xsalsa20poly1305_tweet_open
+#define crypto_box_curve25519xsalsa20poly1305_keypair crypto_box_curve25519xsalsa20poly1305_tweet_keypair
+#define crypto_box_curve25519xsalsa20poly1305_beforenm crypto_box_curve25519xsalsa20poly1305_tweet_beforenm
+#define crypto_box_curve25519xsalsa20poly1305_afternm crypto_box_curve25519xsalsa20poly1305_tweet_afternm
+#define crypto_box_curve25519xsalsa20poly1305_open_afternm crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm
+#define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES
+#define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES
+#define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES
+#define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES
+#define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES
+#define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES
+#define crypto_box_curve25519xsalsa20poly1305_VERSION crypto_box_curve25519xsalsa20poly1305_tweet_VERSION
+#define crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION "crypto_box/curve25519xsalsa20poly1305/tweet"
+#define crypto_core_PRIMITIVE "salsa20"
+#define crypto_core crypto_core_salsa20
+#define crypto_core_OUTPUTBYTES crypto_core_salsa20_OUTPUTBYTES
+#define crypto_core_INPUTBYTES crypto_core_salsa20_INPUTBYTES
+#define crypto_core_KEYBYTES crypto_core_salsa20_KEYBYTES
+#define crypto_core_CONSTBYTES crypto_core_salsa20_CONSTBYTES
+#define crypto_core_IMPLEMENTATION crypto_core_salsa20_IMPLEMENTATION
+#define crypto_core_VERSION crypto_core_salsa20_VERSION
+#define crypto_core_salsa20_tweet_OUTPUTBYTES 64
+#define crypto_core_salsa20_tweet_INPUTBYTES 16
+#define crypto_core_salsa20_tweet_KEYBYTES 32
+#define crypto_core_salsa20_tweet_CONSTBYTES 16
+extern int crypto_core_salsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *);
+#define crypto_core_salsa20_tweet_VERSION "-"
+#define crypto_core_salsa20 crypto_core_salsa20_tweet
+#define crypto_core_salsa20_OUTPUTBYTES crypto_core_salsa20_tweet_OUTPUTBYTES
+#define crypto_core_salsa20_INPUTBYTES crypto_core_salsa20_tweet_INPUTBYTES
+#define crypto_core_salsa20_KEYBYTES crypto_core_salsa20_tweet_KEYBYTES
+#define crypto_core_salsa20_CONSTBYTES crypto_core_salsa20_tweet_CONSTBYTES
+#define crypto_core_salsa20_VERSION crypto_core_salsa20_tweet_VERSION
+#define crypto_core_salsa20_IMPLEMENTATION "crypto_core/salsa20/tweet"
+#define crypto_core_hsalsa20_tweet_OUTPUTBYTES 32
+#define crypto_core_hsalsa20_tweet_INPUTBYTES 16
+#define crypto_core_hsalsa20_tweet_KEYBYTES 32
+#define crypto_core_hsalsa20_tweet_CONSTBYTES 16
+extern int crypto_core_hsalsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *);
+#define crypto_core_hsalsa20_tweet_VERSION "-"
+#define crypto_core_hsalsa20 crypto_core_hsalsa20_tweet
+#define crypto_core_hsalsa20_OUTPUTBYTES crypto_core_hsalsa20_tweet_OUTPUTBYTES
+#define crypto_core_hsalsa20_INPUTBYTES crypto_core_hsalsa20_tweet_INPUTBYTES
+#define crypto_core_hsalsa20_KEYBYTES crypto_core_hsalsa20_tweet_KEYBYTES
+#define crypto_core_hsalsa20_CONSTBYTES crypto_core_hsalsa20_tweet_CONSTBYTES
+#define crypto_core_hsalsa20_VERSION crypto_core_hsalsa20_tweet_VERSION
+#define crypto_core_hsalsa20_IMPLEMENTATION "crypto_core/hsalsa20/tweet"
+#define crypto_hashblocks_PRIMITIVE "sha512"
+#define crypto_hashblocks crypto_hashblocks_sha512
+#define crypto_hashblocks_STATEBYTES crypto_hashblocks_sha512_STATEBYTES
+#define crypto_hashblocks_BLOCKBYTES crypto_hashblocks_sha512_BLOCKBYTES
+#define crypto_hashblocks_IMPLEMENTATION crypto_hashblocks_sha512_IMPLEMENTATION
+#define crypto_hashblocks_VERSION crypto_hashblocks_sha512_VERSION
+#define crypto_hashblocks_sha512_tweet_STATEBYTES 64
+#define crypto_hashblocks_sha512_tweet_BLOCKBYTES 128
+extern int crypto_hashblocks_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long);
+#define crypto_hashblocks_sha512_tweet_VERSION "-"
+#define crypto_hashblocks_sha512 crypto_hashblocks_sha512_tweet
+#define crypto_hashblocks_sha512_STATEBYTES crypto_hashblocks_sha512_tweet_STATEBYTES
+#define crypto_hashblocks_sha512_BLOCKBYTES crypto_hashblocks_sha512_tweet_BLOCKBYTES
+#define crypto_hashblocks_sha512_VERSION crypto_hashblocks_sha512_tweet_VERSION
+#define crypto_hashblocks_sha512_IMPLEMENTATION "crypto_hashblocks/sha512/tweet"
+#define crypto_hashblocks_sha256_tweet_STATEBYTES 32
+#define crypto_hashblocks_sha256_tweet_BLOCKBYTES 64
+extern int crypto_hashblocks_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long);
+#define crypto_hashblocks_sha256_tweet_VERSION "-"
+#define crypto_hashblocks_sha256 crypto_hashblocks_sha256_tweet
+#define crypto_hashblocks_sha256_STATEBYTES crypto_hashblocks_sha256_tweet_STATEBYTES
+#define crypto_hashblocks_sha256_BLOCKBYTES crypto_hashblocks_sha256_tweet_BLOCKBYTES
+#define crypto_hashblocks_sha256_VERSION crypto_hashblocks_sha256_tweet_VERSION
+#define crypto_hashblocks_sha256_IMPLEMENTATION "crypto_hashblocks/sha256/tweet"
+#define crypto_hash_PRIMITIVE "sha512"
+#define crypto_hash crypto_hash_sha512
+#define crypto_hash_BYTES crypto_hash_sha512_BYTES
+#define crypto_hash_IMPLEMENTATION crypto_hash_sha512_IMPLEMENTATION
+#define crypto_hash_VERSION crypto_hash_sha512_VERSION
+#define crypto_hash_sha512_tweet_BYTES 64
+extern int crypto_hash_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long);
+#define crypto_hash_sha512_tweet_VERSION "-"
+#define crypto_hash_sha512 crypto_hash_sha512_tweet
+#define crypto_hash_sha512_BYTES crypto_hash_sha512_tweet_BYTES
+#define crypto_hash_sha512_VERSION crypto_hash_sha512_tweet_VERSION
+#define crypto_hash_sha512_IMPLEMENTATION "crypto_hash/sha512/tweet"
+#define crypto_hash_sha256_tweet_BYTES 32
+extern int crypto_hash_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long);
+#define crypto_hash_sha256_tweet_VERSION "-"
+#define crypto_hash_sha256 crypto_hash_sha256_tweet
+#define crypto_hash_sha256_BYTES crypto_hash_sha256_tweet_BYTES
+#define crypto_hash_sha256_VERSION crypto_hash_sha256_tweet_VERSION
+#define crypto_hash_sha256_IMPLEMENTATION "crypto_hash/sha256/tweet"
+#define crypto_onetimeauth_PRIMITIVE "poly1305"
+#define crypto_onetimeauth crypto_onetimeauth_poly1305
+#define crypto_onetimeauth_verify crypto_onetimeauth_poly1305_verify
+#define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES
+#define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES
+#define crypto_onetimeauth_IMPLEMENTATION crypto_onetimeauth_poly1305_IMPLEMENTATION
+#define crypto_onetimeauth_VERSION crypto_onetimeauth_poly1305_VERSION
+#define crypto_onetimeauth_poly1305_tweet_BYTES 16
+#define crypto_onetimeauth_poly1305_tweet_KEYBYTES 32
+extern int crypto_onetimeauth_poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
+extern int crypto_onetimeauth_poly1305_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
+#define crypto_onetimeauth_poly1305_tweet_VERSION "-"
+#define crypto_onetimeauth_poly1305 crypto_onetimeauth_poly1305_tweet
+#define crypto_onetimeauth_poly1305_verify crypto_onetimeauth_poly1305_tweet_verify
+#define crypto_onetimeauth_poly1305_BYTES crypto_onetimeauth_poly1305_tweet_BYTES
+#define crypto_onetimeauth_poly1305_KEYBYTES crypto_onetimeauth_poly1305_tweet_KEYBYTES
+#define crypto_onetimeauth_poly1305_VERSION crypto_onetimeauth_poly1305_tweet_VERSION
+#define crypto_onetimeauth_poly1305_IMPLEMENTATION "crypto_onetimeauth/poly1305/tweet"
+#define crypto_scalarmult_PRIMITIVE "curve25519"
+#define crypto_scalarmult crypto_scalarmult_curve25519
+#define crypto_scalarmult_base crypto_scalarmult_curve25519_base
+#define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES
+#define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES
+#define crypto_scalarmult_IMPLEMENTATION crypto_scalarmult_curve25519_IMPLEMENTATION
+#define crypto_scalarmult_VERSION crypto_scalarmult_curve25519_VERSION
+#define crypto_scalarmult_curve25519_tweet_BYTES 32
+#define crypto_scalarmult_curve25519_tweet_SCALARBYTES 32
+extern int crypto_scalarmult_curve25519_tweet(unsigned char *,const unsigned char *,const unsigned char *);
+extern int crypto_scalarmult_curve25519_tweet_base(unsigned char *,const unsigned char *);
+#define crypto_scalarmult_curve25519_tweet_VERSION "-"
+#define crypto_scalarmult_curve25519 crypto_scalarmult_curve25519_tweet
+#define crypto_scalarmult_curve25519_base crypto_scalarmult_curve25519_tweet_base
+#define crypto_scalarmult_curve25519_BYTES crypto_scalarmult_curve25519_tweet_BYTES
+#define crypto_scalarmult_curve25519_SCALARBYTES crypto_scalarmult_curve25519_tweet_SCALARBYTES
+#define crypto_scalarmult_curve25519_VERSION crypto_scalarmult_curve25519_tweet_VERSION
+#define crypto_scalarmult_curve25519_IMPLEMENTATION "crypto_scalarmult/curve25519/tweet"
+#define crypto_secretbox_PRIMITIVE "xsalsa20poly1305"
+#define crypto_secretbox crypto_secretbox_xsalsa20poly1305
+#define crypto_secretbox_open crypto_secretbox_xsalsa20poly1305_open
+#define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES
+#define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES
+#define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES
+#define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES
+#define crypto_secretbox_IMPLEMENTATION crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION
+#define crypto_secretbox_VERSION crypto_secretbox_xsalsa20poly1305_VERSION
+#define crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES 32
+#define crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES 24
+#define crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES 32
+#define crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES 16
+extern int crypto_secretbox_xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
+extern int crypto_secretbox_xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
+#define crypto_secretbox_xsalsa20poly1305_tweet_VERSION "-"
+#define crypto_secretbox_xsalsa20poly1305 crypto_secretbox_xsalsa20poly1305_tweet
+#define crypto_secretbox_xsalsa20poly1305_open crypto_secretbox_xsalsa20poly1305_tweet_open
+#define crypto_secretbox_xsalsa20poly1305_KEYBYTES crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES
+#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES
+#define crypto_secretbox_xsalsa20poly1305_ZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES
+#define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES
+#define crypto_secretbox_xsalsa20poly1305_VERSION crypto_secretbox_xsalsa20poly1305_tweet_VERSION
+#define crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION "crypto_secretbox/xsalsa20poly1305/tweet"
+#define crypto_sign_PRIMITIVE "ed25519"
+#define crypto_sign crypto_sign_ed25519
+#define crypto_sign_open crypto_sign_ed25519_open
+#define crypto_sign_keypair crypto_sign_ed25519_keypair
+#define crypto_sign_BYTES crypto_sign_ed25519_BYTES
+#define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES
+#define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES
+#define crypto_sign_IMPLEMENTATION crypto_sign_ed25519_IMPLEMENTATION
+#define crypto_sign_VERSION crypto_sign_ed25519_VERSION
+#define crypto_sign_ed25519_tweet_BYTES 64
+#define crypto_sign_ed25519_tweet_PUBLICKEYBYTES 32
+#define crypto_sign_ed25519_tweet_SECRETKEYBYTES 64
+extern int crypto_sign_ed25519_tweet(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *);
+extern int crypto_sign_ed25519_tweet_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *);
+extern int crypto_sign_ed25519_tweet_keypair(unsigned char *,unsigned char *);
+#define crypto_sign_ed25519_tweet_VERSION "-"
+#define crypto_sign_ed25519 crypto_sign_ed25519_tweet
+#define crypto_sign_ed25519_open crypto_sign_ed25519_tweet_open
+#define crypto_sign_ed25519_keypair crypto_sign_ed25519_tweet_keypair
+#define crypto_sign_ed25519_BYTES crypto_sign_ed25519_tweet_BYTES
+#define crypto_sign_ed25519_PUBLICKEYBYTES crypto_sign_ed25519_tweet_PUBLICKEYBYTES
+#define crypto_sign_ed25519_SECRETKEYBYTES crypto_sign_ed25519_tweet_SECRETKEYBYTES
+#define crypto_sign_ed25519_VERSION crypto_sign_ed25519_tweet_VERSION
+#define crypto_sign_ed25519_IMPLEMENTATION "crypto_sign/ed25519/tweet"
+#define crypto_stream_PRIMITIVE "xsalsa20"
+#define crypto_stream crypto_stream_xsalsa20
+#define crypto_stream_xor crypto_stream_xsalsa20_xor
+#define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES
+#define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES
+#define crypto_stream_IMPLEMENTATION crypto_stream_xsalsa20_IMPLEMENTATION
+#define crypto_stream_VERSION crypto_stream_xsalsa20_VERSION
+#define crypto_stream_xsalsa20_tweet_KEYBYTES 32
+#define crypto_stream_xsalsa20_tweet_NONCEBYTES 24
+extern int crypto_stream_xsalsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
+extern int crypto_stream_xsalsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
+#define crypto_stream_xsalsa20_tweet_VERSION "-"
+#define crypto_stream_xsalsa20 crypto_stream_xsalsa20_tweet
+#define crypto_stream_xsalsa20_xor crypto_stream_xsalsa20_tweet_xor
+#define crypto_stream_xsalsa20_KEYBYTES crypto_stream_xsalsa20_tweet_KEYBYTES
+#define crypto_stream_xsalsa20_NONCEBYTES crypto_stream_xsalsa20_tweet_NONCEBYTES
+#define crypto_stream_xsalsa20_VERSION crypto_stream_xsalsa20_tweet_VERSION
+#define crypto_stream_xsalsa20_IMPLEMENTATION "crypto_stream/xsalsa20/tweet"
+#define crypto_stream_salsa20_tweet_KEYBYTES 32
+#define crypto_stream_salsa20_tweet_NONCEBYTES 8
+extern int crypto_stream_salsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
+extern int crypto_stream_salsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
+#define crypto_stream_salsa20_tweet_VERSION "-"
+#define crypto_stream_salsa20 crypto_stream_salsa20_tweet
+#define crypto_stream_salsa20_xor crypto_stream_salsa20_tweet_xor
+#define crypto_stream_salsa20_KEYBYTES crypto_stream_salsa20_tweet_KEYBYTES
+#define crypto_stream_salsa20_NONCEBYTES crypto_stream_salsa20_tweet_NONCEBYTES
+#define crypto_stream_salsa20_VERSION crypto_stream_salsa20_tweet_VERSION
+#define crypto_stream_salsa20_IMPLEMENTATION "crypto_stream/salsa20/tweet"
+#define crypto_verify_PRIMITIVE "16"
+#define crypto_verify crypto_verify_16
+#define crypto_verify_BYTES crypto_verify_16_BYTES
+#define crypto_verify_IMPLEMENTATION crypto_verify_16_IMPLEMENTATION
+#define crypto_verify_VERSION crypto_verify_16_VERSION
+#define crypto_verify_16_tweet_BYTES 16
+extern int crypto_verify_16_tweet(const unsigned char *,const unsigned char *);
+#define crypto_verify_16_tweet_VERSION "-"
+#define crypto_verify_16 crypto_verify_16_tweet
+#define crypto_verify_16_BYTES crypto_verify_16_tweet_BYTES
+#define crypto_verify_16_VERSION crypto_verify_16_tweet_VERSION
+#define crypto_verify_16_IMPLEMENTATION "crypto_verify/16/tweet"
+#define crypto_verify_32_tweet_BYTES 32
+extern int crypto_verify_32_tweet(const unsigned char *,const unsigned char *);
+#define crypto_verify_32_tweet_VERSION "-"
+#define crypto_verify_32 crypto_verify_32_tweet
+#define crypto_verify_32_BYTES crypto_verify_32_tweet_BYTES
+#define crypto_verify_32_VERSION crypto_verify_32_tweet_VERSION
+#define crypto_verify_32_IMPLEMENTATION "crypto_verify/32/tweet"
+#endif

+ 122 - 9
doc/building.rst

@@ -35,18 +35,20 @@ Building with CMake on Ubuntu or Debian
    ccmake ..
    make
 
-Building with CMake on Windows (Visual Studio)
-----------------------------------------------
+Building with CMake on Windows
+------------------------------
 
-- Get and install Python 2.7.x (Python 3.x should work, too) and CMake: https://python.org/downloads, http://www.cmake.org/cmake/resources/software.html
-- Get and install Visual Studio 2015 Preview: https://www.visualstudio.com/downloads/visual-studio-2015-ctp-vs
-- Download the open62541 sources (using git or as a zipfile from github)
-- Open a command shell (cmd) with Administrator rights and run
-
-.. code-block:: bat
+Here we explain the build process for Visual Studio. To build with MinGW, just
+replace the compiler selection in the call to CMake.
 
-   <path-to-python>\Scripts\pip.exe install lxml
+- Download and install
 
+  - Python 2.7.x (Python 3.x should work, too): https://python.org/downloads
+  - Python lxml: https://pypi.python.org/pypi/lxml
+  - CMake: http://www.cmake.org/cmake/resources/software.html
+  - Microsoft Visual Studio 2015 Community Edition: https://www.visualstudio.com/products/visual-studio-community-vs
+    
+- Download the open62541 sources (using git or as a zipfile from github)
 - Open a command shell (cmd) and run
 
 .. code-block:: bat
@@ -58,7 +60,118 @@ Building with CMake on Windows (Visual Studio)
    :: You can use use cmake-gui for a graphical user-interface to select single features
 
 - Then open "build\open62541.sln" in Visual Studio 2015 and build as usual
+
+Building on OS X
+----------------
+
+- Download and install
+
+  - Xcode: https://itunes.apple.com/us/app/xcode/id497799835?ls=1&mt=12
+  - Homebrew: http://brew.sh/
+  - Pip (a package manager for python, may be preinstalled): ``sudo easy_install pip``
+
+- Run the following in a shell
+
+.. code-block:: bash
+
+   brew install cmake
+   brew install libxml2
+   pip install lxml
+   brew install check # for unit tests
+   brew install userspace-rcu # for multi-threading support
+   brew install graphviz doxygen # for documentation generation
+   pip install sphinx # for documentation generation
+
+Follow Ubuntu instructions without the ``apt-get`` commands as these are taken care of by the above packages.
    
 Build Options
 -------------
 
+Generic CMake options
+~~~~~~~~~~~~~~~~~~~~~
+
+**CMAKE_BUILD_TYPE**
+  - RelWithDebInfo: -O2 optimization with debug symbols
+  - Release: -O2 optimization without debug symbols
+  - Debug: -O0 optimization with debug symbols
+  - MinSizeRel: -Os optimization without debug symbols
+
+BUILD_* group
+~~~~~~~~~~~~~
+
+By default only the shared object libopen62541.so or the library open62541.dll
+and open62541.dll.a resp. open62541.lib are build. Additional artifacts can be
+specified by the following options:
+
+**BUILD_DOCUMENTATION**
+   Generate documentation with doxygen
+**BUILD_EXAMPLECLIENT**
+   Compile example clients from client.c. There are a static and a dynamic binary client and client_static, respectively
+**BUILD_EXAMPLESERVER**
+   Compile example server from server.c There are a static and a dynamic binary server and server_static, respectively
+**BUILD_UNIT_TESTS**
+   Compile unit tests with Check framework. The tests can be executed with make test
+**BUILD_EXAMPLES**
+   Compile specific examples from https://github.com/acplt/open62541/blob/master/examples/
+
+ENABLE_* group
+~~~~~~~~~~~~~~
+
+This group contains build options related to the supported OPC UA features.
+
+**ENABLE_ADDNODES**
+   AddNodes services in sever and client
+**ENABLE_AMALGAMATION**
+   Compile a single-file release files open62541.c and open62541.h
+**ENABLE_COVERAGE**
+   Measure the coverage of unit tests
+**ENABLE_EXTERNAL_NAMESPACES**
+   Enable external namespaces in server
+**ENABLE_GNERATE_NAMESPACE0**
+   Enable automatic generation of NS0
+**GENERATE_NAMESPACE0_FILE**
+   File for NS0 generation from namespace0 folder. Default value is Opc.Ua.NodeSet2.xml
+**ENABLE_METHODCALL**
+   Enable method calls in server and client
+**ENABLE_MULTITHREADING**
+   Enable multi-threading support (experimental)
+**ENABLE_SUBSCRIPTONS**
+   Enable subscriptions
+**GENERATE_SELFSIGNED**
+   Generate a self-signed certificate for the server (openSSL required)
+
+EXTENSION_* group
+~~~~~~~~~~~~~~~~~
+
+Extensions mark experimental extensions that are not compliant with IEC 62541 or
+other OPC UA clients
+
+**EXTENSION_STATELESS**
+   Stateless service calls
+**EXTENSION_UDP**
+   UDP network layer
+
+UA_* group
+~~~~~~~~~~
+
+**UA_LOGLEVEL**
+   The level of logging events that are reported
+   - 600: Fatal and all below
+   - 500: Error and all below
+   - 400: Error and all below
+   - 300: Info and all below
+   - 200: Debug and all below
+   - 100: Trace and all below
+
+C precompiler configuration options
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Options that are not inherited from the CMake configuration are defined in
+ua_config.h. Usually there is no need to adjust them.
+
+**UA_NON_LITTLEENDIAN_ARCHITECTURE**
+   Big-endian or mixed endian platform
+**UA_MIXED_ENDIAN**
+   Mixed-endian platform (e.g., ARM7TDMI)
+**UA_ALIGNED_MEMORY_ACCESS**
+   Platform with aligned memory access only (some ARM processors, e.g. Cortex M3/M4 ARM7TDMI etc.)

+ 82 - 83
examples/networklayer_tcp.c

@@ -49,23 +49,30 @@ static void socket_close(UA_Connection *connection) {
     CLOSESOCKET(connection->sockfd);
 }
 
-static UA_StatusCode socket_write(UA_Connection *connection, UA_ByteString *buf, size_t buflen) {
+static UA_StatusCode socket_write(UA_Connection *connection, UA_ByteString *buf) {
     size_t nWritten = 0;
-    while (nWritten < buflen) {
+    while(buf->length > 0 && nWritten < (size_t)buf->length) {
         UA_Int32 n = 0;
         do {
 #ifdef _WIN32
-            n = send((SOCKET)connection->sockfd, (const char*)buf->data, buflen, 0);
+            n = send((SOCKET)connection->sockfd, (const char*)buf->data, (size_t)buf->length, 0);
             const int last_error = WSAGetLastError();
-            if(n < 0 && last_error != WSAEINTR && last_error != WSAEWOULDBLOCK){
+            if(n < 0 && last_error != WSAEINTR && last_error != WSAEWOULDBLOCK) {
                 connection->close(connection);
                 socket_close(connection);
+#ifdef UA_MULTITHREADING
+                UA_ByteString_deleteMembers(buf);
+#endif
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
             }
 #else
-            n = send(connection->sockfd, (const char*)buf->data, buflen, MSG_NOSIGNAL);
-            if(n == -1L && errno != EINTR && errno != EAGAIN){
+            n = send(connection->sockfd, (const char*)buf->data, (size_t)buf->length, MSG_NOSIGNAL);
+            if(n == -1L && errno != EINTR && errno != EAGAIN) {
+                connection->close(connection);
                 socket_close(connection);
+#ifdef UA_MULTITHREADING
+                UA_ByteString_deleteMembers(buf);
+#endif
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
             }
 #endif
@@ -81,16 +88,17 @@ static UA_StatusCode socket_write(UA_Connection *connection, UA_ByteString *buf,
 static UA_StatusCode socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout) {
     response->data = malloc(connection->localConf.recvBufferSize);
     if(!response->data) {
-        UA_ByteString_init(response);
+        response->length = -1;
         return UA_STATUSCODE_GOOD; /* not enough memory retry */
     }
+
     struct timeval tmptv = {0, timeout * 1000};
-    if(0 != setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv, sizeof(struct timeval))){
-		free(response->data);
-        UA_ByteString_init(response);
+    if(0 != setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv, sizeof(struct timeval))) {
+        UA_ByteString_deleteMembers(response);
         socket_close(connection);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
+
     int ret = recv(connection->sockfd, (char*)response->data, connection->localConf.recvBufferSize, 0);
 	if(ret == 0) {
 		free(response->data);
@@ -102,18 +110,17 @@ static UA_StatusCode socket_recv(UA_Connection *connection, UA_ByteString *respo
         UA_ByteString_init(response);
 #ifdef _WIN32
         const int last_error = WSAGetLastError();
-        if(last_error == WSAEINTR || last_error == WSAEWOULDBLOCK) {
+        if(last_error == WSAEINTR || last_error == WSAEWOULDBLOCK)
 #else
-		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
+		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
 #endif
             return UA_STATUSCODE_GOOD; /* retry */
-        } else {
+        else {
             socket_close(connection);
             return UA_STATUSCODE_BADCONNECTIONCLOSED;
         }
     }
     response->length = ret;
-    *response = UA_Connection_completeMessages(connection, *response);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -172,8 +179,9 @@ static void FreeConnectionCallback(UA_Server *server, void *ptr) {
 #define MAXBACKLOG 100
 
 typedef struct {
+    UA_ServerNetworkLayer layer;
+    
     /* config */
-    UA_Logger *logger;
     UA_UInt32 port;
     UA_ConnectionConfig conf; /* todo: rename to localconf. */
 
@@ -192,9 +200,11 @@ typedef struct {
     } *mappings;
 } ServerNetworkLayerTCP;
 
-static UA_StatusCode ServerNetworkLayerGetBuffer(UA_Connection *connection, UA_ByteString *buf) {
+static UA_StatusCode ServerNetworkLayerGetSendBuffer(UA_Connection *connection, UA_Int32 length, UA_ByteString *buf) {
+    if((UA_UInt32)length > connection->remoteConf.recvBufferSize)
+        return UA_STATUSCODE_BADCOMMUNICATIONERROR;
 #ifdef UA_MULTITHREADING
-    return UA_ByteString_newMembers(buf, connection->remoteConf.recvBufferSize);
+    return UA_ByteString_newMembers(buf, length);
 #else
     ServerNetworkLayerTCP *layer = connection->handle;
     *buf = layer->buffer;
@@ -202,27 +212,23 @@ static UA_StatusCode ServerNetworkLayerGetBuffer(UA_Connection *connection, UA_B
 #endif
 }
 
-static void ServerNetworkLayerReleaseBuffer(UA_Connection *connection, UA_ByteString *buf) {
+static void ServerNetworkLayerReleaseSendBuffer(UA_Connection *connection, UA_ByteString *buf) {
 #ifdef UA_MULTITHREADING
     UA_ByteString_deleteMembers(buf);
 #endif
 }
 
+static void ServerNetworkLayerReleaseRecvBuffer(UA_Connection *connection, UA_ByteString *buf) {
+    UA_ByteString_deleteMembers(buf);
+}
+
 /* after every select, we need to reset the sockets we want to listen on */
 static void setFDSet(ServerNetworkLayerTCP *layer) {
     FD_ZERO(&layer->fdset);
-#ifdef _WIN32
     FD_SET((UA_UInt32)layer->serversockfd, &layer->fdset);
-#else
-    FD_SET(layer->serversockfd, &layer->fdset);
-#endif
     layer->highestfd = layer->serversockfd;
     for(size_t i = 0; i < layer->mappingsSize; i++) {
-#ifdef _WIN32
         FD_SET((UA_UInt32)layer->mappings[i].sockfd, &layer->fdset);
-#else
-        FD_SET(layer->mappings[i].sockfd, &layer->fdset);
-#endif
         if(layer->mappings[i].sockfd > layer->highestfd)
             layer->highestfd = layer->mappings[i].sockfd;
     }
@@ -251,13 +257,14 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     c->sockfd = newsockfd;
     c->handle = layer;
     c->localConf = layer->conf;
-    c->write = socket_write;
+    c->send = socket_write;
     c->close = ServerNetworkLayerTCP_closeConnection;
-    c->getBuffer = ServerNetworkLayerGetBuffer;
-    c->releaseBuffer = ServerNetworkLayerReleaseBuffer;
+    c->getSendBuffer = ServerNetworkLayerGetSendBuffer;
+    c->releaseSendBuffer = ServerNetworkLayerReleaseSendBuffer;
+    c->releaseRecvBuffer = ServerNetworkLayerReleaseRecvBuffer;
     c->state = UA_CONNECTION_OPENING;
-    struct ConnectionMapping *nm =
-        realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
+    struct ConnectionMapping *nm;
+    nm = realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
     if(!nm) {
         free(c);
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -268,18 +275,17 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, UA_Logger *logger) {
-    ServerNetworkLayerTCP *layer = nl->handle;
-    layer->logger = logger;
+static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger logger) {
+    layer->layer.logger = logger;
 #ifdef _WIN32
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
-        UA_LOG_WARNING((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Error opening socket, code: %d",
+        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Error opening socket, code: %d",
                        WSAGetLastError());
         return UA_STATUSCODE_BADINTERNALERROR;
     }
 #else
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-        UA_LOG_WARNING((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Error opening socket");
+        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Error opening socket");
         return UA_STATUSCODE_BADINTERNALERROR;
     }
 #endif
@@ -290,25 +296,25 @@ static UA_StatusCode ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, UA_L
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
                   SO_REUSEADDR, (const char *)&optval,
                   sizeof(optval)) == -1) {
-        UA_LOG_WARNING((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Error during setting of socket options");
+        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION,
+                       "Error during setting of socket options");
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
             sizeof(serv_addr)) < 0) {
-        UA_LOG_WARNING((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Error during socket binding");
+        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Error during socket binding");
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     socket_set_nonblocking(layer->serversockfd);
     listen(layer->serversockfd, MAXBACKLOG);
-    UA_LOG_INFO((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Listening on %.*s",
-                nl->discoveryUrl.length, nl->discoveryUrl.data);
+    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Listening on %.*s",
+                layer->layer.discoveryUrl.length, layer->layer.discoveryUrl.data);
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_Int32 ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout) {
-    ServerNetworkLayerTCP *layer = nl->handle;
+static size_t ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UInt16 timeout) {
     setFDSet(layer);
     struct timeval tmptv = {0, timeout};
     UA_Int32 resultsize;
@@ -318,7 +324,7 @@ static UA_Int32 ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job
         if(errno == EINTR)
             goto repeat_select;
         *jobs = NULL;
-        return resultsize;
+        return 0;
     }
 
     /* accept new connections (can only be a single one) */
@@ -343,17 +349,15 @@ static UA_Int32 ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job
         return 0;
 
     /* read from established sockets */
-    UA_Int32 j = 0;
+    size_t j = 0;
     UA_ByteString buf = UA_BYTESTRING_NULL;
-    for(size_t i = 0; i < layer->mappingsSize && j < resultsize; i++) {
+    for(size_t i = 0; i < layer->mappingsSize && j < (size_t)resultsize; i++) {
         if(!(FD_ISSET(layer->mappings[i].sockfd, &layer->fdset)))
             continue;
         if(socket_recv(layer->mappings[i].connection, &buf, 0) == UA_STATUSCODE_GOOD) {
             if(!buf.data)
                 continue;
-            js[j].type = UA_JOBTYPE_BINARYMESSAGE;
-            js[j].job.binaryMessage.message = buf;
-            js[j].job.binaryMessage.connection = layer->mappings[i].connection;
+            js[j] = UA_Connection_completeMessages(layer->mappings[i].connection, buf);
         } else {
             UA_Connection *c = layer->mappings[i].connection;
             /* the socket is already closed */
@@ -363,15 +367,14 @@ static UA_Int32 ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job
             layer->mappingsSize--;
             j++;
             i--; // iterate over the same index again
-            js[j].type = UA_JOBTYPE_DELAYEDMETHODCALL;
+            js[j].type = UA_JOBTYPE_METHODCALL_DELAYED;
             js[j].job.methodCall.method = FreeConnectionCallback;
             js[j].job.methodCall.data = c;
         }
         j++;
     }
 
-    if (j == 0)
-    {
+    if(j == 0) {
     	free(js);
     	js = NULL;
     }
@@ -380,8 +383,7 @@ static UA_Int32 ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job
     return j;
 }
 
-static UA_Int32 ServerNetworkLayerTCP_stop(UA_ServerNetworkLayer *nl, UA_Job **jobs) {
-    ServerNetworkLayerTCP *layer = nl->handle;
+static size_t ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Job **jobs) {
     UA_Job *items = malloc(sizeof(UA_Job) * layer->mappingsSize * 2);
     if(!items)
         return 0;
@@ -389,7 +391,7 @@ static UA_Int32 ServerNetworkLayerTCP_stop(UA_ServerNetworkLayer *nl, UA_Job **j
         socket_close(layer->mappings[i].connection);
         items[i*2].type = UA_JOBTYPE_DETACHCONNECTION;
         items[i*2].job.closeConnection = layer->mappings[i].connection;
-        items[(i*2)+1].type = UA_JOBTYPE_DELAYEDMETHODCALL;
+        items[(i*2)+1].type = UA_JOBTYPE_METHODCALL_DELAYED;
         items[(i*2)+1].job.methodCall.method = FreeConnectionCallback;
         items[(i*2)+1].job.methodCall.data = layer->mappings[i].connection;
     }
@@ -401,56 +403,52 @@ static UA_Int32 ServerNetworkLayerTCP_stop(UA_ServerNetworkLayer *nl, UA_Job **j
 }
 
 /* run only when the server is stopped */
-static void ServerNetworkLayerTCP_deleteMembers(UA_ServerNetworkLayer *nl) {
-    ServerNetworkLayerTCP *layer = nl->handle;
+static void ServerNetworkLayerTCP_deleteMembers(ServerNetworkLayerTCP *layer) {
 #ifndef UA_MULTITHREADING
     UA_ByteString_deleteMembers(&layer->buffer);
 #endif
     for(size_t i = 0; i < layer->mappingsSize; i++)
         free(layer->mappings[i].connection);
     free(layer->mappings);
-    free(layer);
 }
 
-UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
+UA_ServerNetworkLayer * ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
 #ifdef _WIN32
     WORD wVersionRequested;
     WSADATA wsaData;
     wVersionRequested = MAKEWORD(2, 2);
     WSAStartup(wVersionRequested, &wsaData);
 #endif
-    UA_ServerNetworkLayer nl;
-    memset(&nl, 0, sizeof(UA_ServerNetworkLayer));
-
     ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
-    if(!layer){
-        return nl;
-    }
+    if(!layer)
+        return NULL;
+    memset(layer, 0, sizeof(ServerNetworkLayerTCP));
     layer->conf = conf;
     layer->mappingsSize = 0;
     layer->mappings = NULL;
     layer->port = port;
     char hostname[256];
     gethostname(hostname, 255);
-    UA_String_copyprintf("opc.tcp://%s:%d", &nl.discoveryUrl, hostname, port);
+    UA_String_copyprintf("opc.tcp://%s:%d", &layer->layer.discoveryUrl, hostname, port);
 
 #ifndef UA_MULTITHREADING
     layer->buffer = (UA_ByteString){.length = conf.maxMessageSize, .data = malloc(conf.maxMessageSize)};
 #endif
 
-    nl.handle = layer;
-    nl.start = ServerNetworkLayerTCP_start;
-    nl.getJobs = ServerNetworkLayerTCP_getJobs;
-    nl.stop = ServerNetworkLayerTCP_stop;
-    nl.deleteMembers = ServerNetworkLayerTCP_deleteMembers;
-    return nl;
+    layer->layer.start = (UA_StatusCode(*)(UA_ServerNetworkLayer*,UA_Logger))ServerNetworkLayerTCP_start;
+    layer->layer.getJobs = (size_t(*)(UA_ServerNetworkLayer*,UA_Job**,UA_UInt16))ServerNetworkLayerTCP_getJobs;
+    layer->layer.stop = (size_t(*)(UA_ServerNetworkLayer*, UA_Job**))ServerNetworkLayerTCP_stop;
+    layer->layer.deleteMembers = (void(*)(UA_ServerNetworkLayer*))ServerNetworkLayerTCP_deleteMembers;
+    return &layer->layer;
 }
 
 /***************************/
 /* Client NetworkLayer TCP */
 /***************************/
 
-static UA_StatusCode ClientNetworkLayerGetBuffer(UA_Connection *connection, UA_ByteString *buf) {
+static UA_StatusCode ClientNetworkLayerGetBuffer(UA_Connection *connection, UA_Int32 length, UA_ByteString *buf) {
+    if((UA_UInt32)length > connection->remoteConf.recvBufferSize)
+        return UA_STATUSCODE_BADCOMMUNICATIONERROR;
 #ifndef UA_MULTITHREADING
     if(connection->state == UA_CONNECTION_CLOSED)
         return UA_STATUSCODE_BADCONNECTIONCLOSED;
@@ -480,12 +478,11 @@ static void ClientNetworkLayerClose(UA_Connection *connection) {
 }
 
 /* we have no networklayer. instead, attach the reusable buffer to the handle */
-UA_Connection ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, char *endpointUrl,
-                                            UA_Logger *logger) {
+UA_Connection
+ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, char *endpointUrl, UA_Logger logger) {
     UA_Connection connection;
     UA_Connection_init(&connection);
     connection.localConf = localConf;
-
 #ifndef UA_MULTITHREADING
     connection.handle = UA_ByteString_new();
     UA_ByteString_newMembers(connection.handle, localConf.maxMessageSize);
@@ -502,8 +499,8 @@ UA_Connection ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, char
     }
 
     UA_UInt16 portpos = 9;
-    UA_UInt16 port = 0;
-    for(;portpos < urlLength-1; portpos++) {
+    UA_UInt16 port;
+    for(port = 0; portpos < urlLength-1; portpos++) {
         if(endpointUrl[portpos] == ':') {
             port = atoi(&endpointUrl[portpos+1]);
             break;
@@ -531,7 +528,7 @@ UA_Connection ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, char
         return connection;
     }
     struct hostent *server = gethostbyname(hostname);
-    if(server == NULL) {
+    if(!server) {
         UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "DNS lookup of %s failed", hostname);
         return connection;
     }
@@ -549,16 +546,18 @@ UA_Connection ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, char
 
 #ifdef SO_NOSIGPIPE
     int val = 1;
-    if (setsockopt(connection.sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val)) < 0) {
-    UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Couldn't set SO_NOSIGPIPE");
+    if(setsockopt(connection.sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val)) < 0) {
+        UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Couldn't set SO_NOSIGPIPE");
+        return connection;
     }
 #endif
 
     //socket_set_nonblocking(connection.sockfd);
-    connection.write = socket_write;
+    connection.send = socket_write;
     connection.recv = socket_recv;
     connection.close = ClientNetworkLayerClose;
-    connection.getBuffer = ClientNetworkLayerGetBuffer;
-    connection.releaseBuffer = ClientNetworkLayerReleaseBuffer;
+    connection.getSendBuffer = ClientNetworkLayerGetBuffer;
+    connection.releaseSendBuffer = ClientNetworkLayerReleaseBuffer;
+    connection.releaseRecvBuffer = ClientNetworkLayerReleaseBuffer;
     return connection;
 }

+ 4 - 2
examples/networklayer_tcp.h

@@ -14,8 +14,10 @@ extern "C" {
 #include "ua_client.h"
 
 /** @brief Create the TCP networklayer and listen to the specified port */
-UA_EXPORT UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
-UA_EXPORT UA_Connection ClientNetworkLayerTCP_connect(UA_ConnectionConfig conf, char *endpointUrl, UA_Logger *logger);
+UA_ServerNetworkLayer UA_EXPORT * ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
+
+UA_Connection UA_EXPORT
+ClientNetworkLayerTCP_connect(UA_ConnectionConfig conf, char *endpointUrl, UA_Logger logger);
 
 #ifdef __cplusplus
 } // extern "C"

+ 92 - 95
examples/networklayer_udp.c

@@ -32,17 +32,17 @@
 #define MAXBACKLOG 100
 
 #ifdef _WIN32
-# error fixme: udp not yet implemented for windows
+# error udp not yet implemented for windows
 #endif
 
 /*****************************/
 /* Generic Buffer Management */
 /*****************************/
 
-static UA_StatusCode GetMallocedBuffer(UA_Connection *connection, UA_ByteString *buf, size_t minSize) {
-    if(minSize > connection->remoteConf.recvBufferSize)
-        return UA_STATUSCODE_BADINTERNALERROR;
-    return UA_ByteString_newMembers(buf, minSize);
+static UA_StatusCode GetMallocedBuffer(UA_Connection *connection, UA_Int32 length, UA_ByteString *buf) {
+    if((UA_UInt32)length > connection->remoteConf.recvBufferSize)
+        return UA_STATUSCODE_BADCOMMUNICATIONERROR;
+    return UA_ByteString_newMembers(buf, connection->remoteConf.recvBufferSize);
 }
 
 static void ReleaseMallocedBuffer(UA_Connection *connection, UA_ByteString *buf) {
@@ -62,50 +62,46 @@ typedef struct {
 } UDPConnection;
 
 typedef struct {
-    UA_Server *server;
+    UA_ServerNetworkLayer layer;
 	UA_ConnectionConfig conf;
 	fd_set fdset;
 	UA_Int32 serversockfd;
     UA_UInt32 port;
-    UA_Logger *logger;
 } ServerNetworkLayerUDP;
 
 /** Accesses only the sockfd in the handle. Can be run from parallel threads. */
-static void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
-	UA_UInt32 total_len = 0, nWritten = 0;
-	struct iovec iov[gather_buf.stringsSize];
-	for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
-		iov[i] = (struct iovec) {.iov_base = gather_buf.strings[i].data,
-                                 .iov_len = gather_buf.strings[i].length};
-		total_len += gather_buf.strings[i].length;
-	}
+static UA_StatusCode sendUDP(UA_Connection *connection, UA_ByteString *buf) {
+    UDPConnection *udpc = (UDPConnection*)connection;
+    ServerNetworkLayerUDP *layer = (ServerNetworkLayerUDP*)connection->handle;
+	size_t nWritten = 0;
 	struct sockaddr_in *sin = NULL;
-	if (handle->from.sa_family == AF_INET) {
+
+	if (udpc->from.sa_family == AF_INET) {
 #if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-align"
 #endif
-	    sin = (struct sockaddr_in *) &(handle->from);
+	    sin = (struct sockaddr_in *) &udpc->from;
 #if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic pop
 #endif
 	} else {
-		//FIXME:
-		return;
-	}
-	struct msghdr message = {.msg_name = sin, .msg_namelen = handle->fromlen, .msg_iov = iov,
-							 .msg_iovlen = gather_buf.stringsSize, .msg_control = NULL,
-							 .msg_controllen = 0, .msg_flags = 0};
-	while (nWritten < total_len) {
-		UA_Int32 n = 0;
-		do {
-            n = sendmsg(((ServerNetworkLayerUDP*)handle->connection.handle)->serversockfd, &message, 0);
-            if(n == -1L) {
-            	printf("ERROR:%i\n", errno);
-            }
-        } while (n == -1L && errno == EINTR);
+        UA_ByteString_deleteMembers(buf);
+		return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+	while (nWritten < (size_t)buf->length) {
+		UA_Int32 n = sendto(layer->serversockfd, buf->data, buf->length, 0,
+                            (struct sockaddr*)sin, sizeof(struct sockaddr_in));
+        if(n == -1L) {
+            UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "UDP send error %i", errno);
+            UA_ByteString_deleteMembers(buf);
+            return UA_STATUSCODE_BADINTERNALERROR;
+        }
         nWritten += n;
 	}
+    UA_ByteString_deleteMembers(buf);
+    return UA_STATUSCODE_GOOD;
 }
 
 static UA_StatusCode socket_set_nonblocking(UA_Int32 sockfd) {
@@ -120,14 +116,15 @@ static void setFDSet(ServerNetworkLayerUDP *layer) {
 	FD_SET(layer->serversockfd, &layer->fdset);
 }
 
-static void closeConnectionUDP(UDPConnection *handle) {
+static void closeConnectionUDP(UA_Connection *handle) {
 	free(handle);
 }
 
-static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, UA_Logger *logger) {
-    layer->logger = logger;
-    if((layer->serversockfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
-		perror("ERROR opening socket");
+static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, UA_Logger logger) {
+    layer->layer.logger = logger;
+    layer->serversockfd = socket(PF_INET, SOCK_DGRAM, 0);
+    if(layer->serversockfd < 0) {
+		UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Error opening socket");
 		return UA_STATUSCODE_BADINTERNALERROR;
 	} 
 	const struct sockaddr_in serv_addr =
@@ -135,98 +132,98 @@ static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, U
          .sin_port = htons(layer->port), .sin_zero = {0}};
 	int optval = 1;
 	if(setsockopt(layer->serversockfd, SOL_SOCKET,
-                  SO_REUSEADDR, (const char *)&optval,
-                  sizeof(optval)) == -1) {
-		perror("setsockopt");
+                  SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
+        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Could not setsockopt");
 		CLOSESOCKET(layer->serversockfd);
 		return UA_STATUSCODE_BADINTERNALERROR;
 	}
 	if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
             sizeof(serv_addr)) < 0) {
-		perror("binding");
+        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Could not bind the socket");
 		CLOSESOCKET(layer->serversockfd);
 		return UA_STATUSCODE_BADINTERNALERROR;
 	}
 	socket_set_nonblocking(layer->serversockfd);
-    printf("Listening for UDP connections on %s:%d", inet_ntoa(serv_addr.sin_addr),
-           ntohs(serv_addr.sin_port));
+    UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Listening for UDP connections on %s:%d",
+                   inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port));
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_Int32 ServerNetworkLayerUDP_getWork(ServerNetworkLayerUDP *layer, UA_WorkItem **workItems,
-                                              UA_UInt16 timeout) {
-    UA_WorkItem *items = NULL;
+static size_t ServerNetworkLayerUDP_getJobs(ServerNetworkLayerUDP *layer, UA_Job **jobs, UA_UInt16 timeout) {
+    UA_Job *items = NULL;
     setFDSet(layer);
     struct timeval tmptv = {0, timeout};
     UA_Int32 resultsize = select(layer->serversockfd+1, &layer->fdset, NULL, NULL, &tmptv);
     if(resultsize <= 0 || !FD_ISSET(layer->serversockfd, &layer->fdset)) {
-        *workItems = items;
+        *jobs = items;
         return 0;
     }
-    items = malloc(sizeof(UA_WorkItem)*(resultsize));
+    items = malloc(sizeof(UA_Job)*resultsize);
 	// read from established sockets
     UA_Int32 j = 0;
 	UA_ByteString buf = {-1, NULL};
-		if(!buf.data) {
-			buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
-			if(!buf.data)
-				printf("malloc failed");
-		}
-		struct sockaddr sender;
-		socklen_t sendsize = sizeof(sender);
-		bzero(&sender, sizeof(sender));
-        buf.length = recvfrom(layer->serversockfd, buf.data, layer->conf.recvBufferSize, 0, &sender, &sendsize);
-        if (buf.length <= 0) {
-        } else {
-            UDPConnection *c = malloc(sizeof(UDPConnection));
-        	if(!c)
-        		return UA_STATUSCODE_BADINTERNALERROR;
-            c->from = sender;
-            c->fromlen = sendsize;
-            c->connection.state = UA_CONNECTION_OPENING;
-            c->connection.localConf = layer->conf;
-            c->connection.channel = NULL;
-            c->connection.close = (void (*)(UA_Connection*))closeConnectionUDP;
-            c->connection.write = (UA_StatusCode (*)(UA_Connection*, UA_ByteStringArray))writeCallbackUDP;
-            c->connection.getBuffer = GetMallocedBuffer;
-            c->connection.releaseBuffer = ReleaseMallocedBuffer;
-            c->connection.handle = layer;
-            items[j].type = UA_WORKITEMTYPE_BINARYMESSAGE;
-            items[j].work.binaryMessage.message = buf;
-            items[j].work.binaryMessage.connection = (UA_Connection*)c;
-            buf.data = NULL;
-            j++;
-        }
+    if(!buf.data) {
+        buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
+        if(!buf.data)
+            UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "malloc failed");
+    }
+    struct sockaddr sender;
+    socklen_t sendsize = sizeof(sender);
+    bzero(&sender, sizeof(sender));
+    buf.length = recvfrom(layer->serversockfd, buf.data, layer->conf.recvBufferSize, 0, &sender, &sendsize);
+    if (buf.length <= 0) {
+    } else {
+        UDPConnection *c = malloc(sizeof(UDPConnection));
+        if(!c)
+            return UA_STATUSCODE_BADINTERNALERROR;
+        UA_Connection_init(&c->connection);
+        c->from = sender;
+        c->fromlen = sendsize;
+        // c->sockfd = newsockfd;
+        c->connection.getSendBuffer = GetMallocedBuffer;
+        c->connection.releaseSendBuffer = ReleaseMallocedBuffer;
+        c->connection.releaseRecvBuffer = ReleaseMallocedBuffer;
+        c->connection.handle = layer;
+        c->connection.send = sendUDP;
+        c->connection.close = closeConnectionUDP;
+        c->connection.localConf = layer->conf;
+        c->connection.state = UA_CONNECTION_OPENING;
+
+        items[j].type = UA_JOBTYPE_BINARYMESSAGE_NETWORKLAYER;
+        items[j].job.binaryMessage.message = buf;
+        items[j].job.binaryMessage.connection = (UA_Connection*)c;
+        buf.data = NULL;
+        j++;
+    }
     if(buf.data)
         free(buf.data);
     if(j == 0) {
         free(items);
-        *workItems = NULL;
+        *jobs = NULL;
     } else
-        *workItems = items;
+        *jobs = items;
     return j;
 }
 
-static UA_Int32 ServerNetworkLayerUDP_stop(ServerNetworkLayerUDP * layer, UA_WorkItem **workItems) {
+static UA_Int32 ServerNetworkLayerUDP_stop(ServerNetworkLayerUDP * layer, UA_Job **jobs) {
 	CLOSESOCKET(layer->serversockfd);
 	return 0;
 }
 
-static void ServerNetworkLayerUDP_delete(ServerNetworkLayerUDP *layer) {
-	free(layer);
+static void ServerNetworkLayerUDP_deleteMembers(ServerNetworkLayerUDP *layer) {
 }
 
-UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
-    ServerNetworkLayerUDP *udplayer = malloc(sizeof(ServerNetworkLayerUDP));
-	udplayer->conf = conf;
-    udplayer->port = port;
-
-    UA_ServerNetworkLayer nl;
-    nl.nlHandle = udplayer;
-    nl.start = (UA_StatusCode (*)(void*, UA_Logger *logger))ServerNetworkLayerUDP_start;
-    nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) ServerNetworkLayerUDP_getWork;
-    nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) ServerNetworkLayerUDP_stop;
-    nl.free = (void (*)(void*))ServerNetworkLayerUDP_delete;
-    nl.discoveryUrl = NULL;
-    return nl;
+UA_ServerNetworkLayer * ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
+    ServerNetworkLayerUDP *layer = malloc(sizeof(ServerNetworkLayerUDP));
+    if(!layer)
+        return NULL;
+    memset(layer, 0, sizeof(ServerNetworkLayerUDP));
+
+	layer->conf = conf;
+    layer->port = port;
+    layer->layer.start = (UA_StatusCode(*)(UA_ServerNetworkLayer*,UA_Logger))ServerNetworkLayerUDP_start;
+    layer->layer.getJobs = (size_t(*)(UA_ServerNetworkLayer*,UA_Job**,UA_UInt16))ServerNetworkLayerUDP_getJobs;
+    layer->layer.stop = (size_t(*)(UA_ServerNetworkLayer*, UA_Job**))ServerNetworkLayerUDP_stop;
+    layer->layer.deleteMembers = (void(*)(UA_ServerNetworkLayer*))ServerNetworkLayerUDP_deleteMembers;
+    return &layer->layer;
 }

+ 6 - 6
examples/networklayer_udp.h

@@ -10,14 +10,14 @@
 extern "C" {
 #endif
 
-#ifdef NOT_AMALGATED
-# include "ua_server.h"
-#else
-# include "open62541.h"
-#endif
+#include "ua_server.h"
+#include "ua_client.h"
 
 /** @brief Create the UDP networklayer and listen to the specified port */
-UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port);
+UA_ServerNetworkLayer UA_EXPORT * ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port);
+
+UA_Connection UA_EXPORT
+ClientNetworkLayerUDP_connect(UA_ConnectionConfig conf, char endpointUrl[], UA_Logger logger);
 
 #ifdef __cplusplus
 } // extern "C"

+ 9 - 8
examples/server_udp.c

@@ -3,14 +3,13 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
 #include <time.h>
-#include "ua_types.h"
-
 #include <stdio.h>
 #include <stdlib.h> 
 #include <signal.h>
 
 // provided by the open62541 lib
-#include "ua_server.h"
+# include "ua_types.h"
+# include "ua_server.h"
 
 // provided by the user, implementations available in the /examples folder
 #include "logger_stdout.h"
@@ -26,8 +25,9 @@ static void stopHandler(int sign) {
 int main(int argc, char** argv) {
 	signal(SIGINT, stopHandler); /* catches ctrl-c */
 
-	UA_Server *server = UA_Server_new();
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerUDP_new(UA_ConnectionConfig_standard, 16664));
+	UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+    UA_ServerNetworkLayer *nl = ServerNetworkLayerUDP_new(UA_ConnectionConfig_standard, 16664);
+    UA_Server_addNetworkLayer(server, nl);
 
 	// add a variable node to the adresspace
     UA_Variant *myIntegerVariant = UA_Variant_new();
@@ -35,11 +35,12 @@ int main(int argc, char** argv) {
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+    UA_LocalizedText myIntegerBrowseName = UA_LOCALIZEDTEXT("en_US","the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
-                              myIntegerNodeId, parentNodeId, parentReferenceNodeId);
-
+    UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, myIntegerBrowseName,
+                              myIntegerBrowseName, 0,0,
+                              parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
 
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
 	UA_Server_delete(server);

+ 11 - 0
examples/server_variable.c

@@ -22,6 +22,14 @@ static void stopHandler(int sign) {
     running = 0;
 }
 
+static void onRead(void *handle, const UA_NodeId nodeid,  const UA_Variant *data, const UA_NumericRange *range){
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "onRead; handle is: %i", (uintptr_t)handle);
+}
+
+static void onWrite(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range){
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "onWrite; handle is: %i", (uintptr_t)handle);
+}
+
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
@@ -44,6 +52,9 @@ int main(int argc, char** argv) {
     UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, myIntegerBrowseName, myIntegerBrowseName, 0, 0,
                               parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
 
+    UA_ValueCallback callback = {(void*)7, onRead, onWrite};
+    UA_Server_setAttribute_valueCallback(server, myIntegerNodeId, callback);
+
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_Server_delete(server);
 

+ 1 - 1
include/ua_client.h

@@ -19,7 +19,7 @@ typedef struct UA_Client UA_Client;
  * successfully connecting.
  */
 typedef UA_Connection (*UA_ConnectClientConnection)(UA_ConnectionConfig localConf, char *endpointUrl,
-                                                    UA_Logger *logger);
+                                                    UA_Logger logger);
 
 typedef struct UA_ClientConfig {
     UA_Int32 timeout; //sync response timeout

+ 31 - 26
include/ua_connection.h

@@ -21,12 +21,7 @@ extern "C" {
 #endif
 
 #include "ua_types.h"
-
-/**
- * @defgroup communication Communication
- *
- * @{
- */
+#include "ua_job.h"
 
 typedef enum UA_ConnectionState {
     UA_CONNECTION_OPENING, ///< The socket is open, but the HEL/ACK handshake is not done
@@ -48,9 +43,6 @@ extern const UA_EXPORT UA_ConnectionConfig UA_ConnectionConfig_standard;
 struct UA_SecureChannel;
 typedef struct UA_SecureChannel UA_SecureChannel;
 
-struct UA_Connection;
-typedef struct UA_Connection UA_Connection;
-
 /**
  * The connection to a single client (or server). The connection is defined independent of the
  * underlying network layer implementation. This allows a plugging-in custom implementations (e.g.
@@ -60,29 +52,42 @@ struct UA_Connection {
     UA_ConnectionState state;
     UA_ConnectionConfig localConf;
     UA_ConnectionConfig remoteConf;
-    UA_SecureChannel *channel; ///> The securechannel that is attached to this connection (or null)
-    UA_Int32 sockfd; ///> Most connectivity solutions run on sockets. Having the socket id here simplifies the design.
-    void *handle; ///> A pointer to the networklayer
-    UA_ByteString incompleteMessage; ///> Half-received messages (tcp is a streaming protocol) get stored here
-    UA_StatusCode (*getBuffer)(UA_Connection *connection, UA_ByteString *buf); ///> Get a buffer of the maximum remote recv size
-    void (*releaseBuffer)(UA_Connection *connection, UA_ByteString *buf); ///> Release the buffer manually
+    UA_SecureChannel *channel; ///< The securechannel that is attached to this connection (or null)
+    UA_Int32 sockfd; ///< Most connectivity solutions run on sockets. Having the socket id here
+                     ///  simplifies the design.
+    void *handle; ///< A pointer to the networklayer
+    UA_ByteString incompleteMessage; ///< A half-received message (TCP is a streaming protocol) is stored here
+
+    /** Get a buffer for sending */
+    UA_StatusCode (*getSendBuffer)(UA_Connection *connection, UA_Int32 length, UA_ByteString *buf);
+
+    /** Release the send buffer manually */
+    void (*releaseSendBuffer)(UA_Connection *connection, UA_ByteString *buf);
+
     /**
      * Sends a message over the connection.
      * @param connection The connection
-     * @param buf The message buffer is potentially reused (or freed) internally if sending succeeds.
-     * @param buflen Since the buffer is potentially reused, we provide a separate content length.
+     * @param buf The message buffer is always released (freed) internally
      * @return Returns an error code or UA_STATUSCODE_GOOD.
      */
-    UA_StatusCode (*write)(UA_Connection *connection, UA_ByteString *buf, size_t buflen);
+    UA_StatusCode (*send)(UA_Connection *connection, UA_ByteString *buf);
+
    /**
      * Receive a message from the remote connection
 	 * @param connection The connection
-	 * @param response The response string. It is allocated by the connection and needs to be freed with connection->releaseBuffer
+	 * @param response The response string. It is allocated by the connection and needs to be freed
+              with connection->releaseBuffer
      * @param timeout Timeout of the recv operation in milliseconds
-     * @return Returns UA_STATUSCODE_BADCOMMUNICATIONERROR if the recv operation can be repeated, UA_STATUSCODE_GOOD if it succeeded and
-     * UA_STATUSCODE_BADCONNECTIONCLOSED if the connection was closed.
+     * @return Returns UA_STATUSCODE_BADCOMMUNICATIONERROR if the recv operation can be repeated,
+     *         UA_STATUSCODE_GOOD if it succeeded and UA_STATUSCODE_BADCONNECTIONCLOSED if the
+     *         connection was closed.
 	 */
     UA_StatusCode (*recv)(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout);
+
+    /** Release the buffer of a received message */
+    void (*releaseRecvBuffer)(UA_Connection *connection, UA_ByteString *buf);
+
+    /** Close the connection */
     void (*close)(UA_Connection *connection);
 };
 
@@ -92,11 +97,11 @@ void UA_EXPORT UA_Connection_deleteMembers(UA_Connection *connection);
 void UA_EXPORT UA_Connection_detachSecureChannel(UA_Connection *connection);
 void UA_EXPORT UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel);
 
-/** Returns a string of complete message (the length entry is decoded for that).
-    If the received message is incomplete, it is retained in the connection. */
-UA_ByteString UA_EXPORT UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received);
-
-/** @} */
+/** Returns a job that contains either a message-bytestring managed by the network layer or a
+    message-bytestring that was newly allocated (or a nothing-job). Half-received messages are
+    attached to the connection. The next completion tries to create a complete message with the next
+    buffer the connection receives. */
+UA_Job UA_EXPORT UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received);
 
 #ifdef __cplusplus
 } // extern "C"

+ 56 - 0
include/ua_job.h

@@ -0,0 +1,56 @@
+ /*
+ * Copyright (C) 2014 the contributors as stated in the AUTHORS file
+ *
+ * This file is part of open62541. open62541 is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License, version 3 (as published by the Free Software Foundation) with
+ * a static linking exception as stated in the LICENSE file provided with
+ * open62541.
+ *
+ * open62541 is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ */
+
+#ifndef UA_JOB_H_
+#define UA_JOB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct UA_Connection;
+typedef struct UA_Connection UA_Connection;
+
+struct UA_Server;
+typedef struct UA_Server UA_Server;
+
+/** Jobs describe work that is executed once or repeatedly in the server */
+typedef struct {
+    enum {
+        UA_JOBTYPE_NOTHING, ///< Guess what?
+        UA_JOBTYPE_DETACHCONNECTION, ///< Detach the connection from the secure channel (but don't delete it)
+        UA_JOBTYPE_BINARYMESSAGE_NETWORKLAYER, ///< The binary message is memory managed by the networklayer
+        UA_JOBTYPE_BINARYMESSAGE_ALLOCATED, ///< The binary message was relocated away from the networklayer
+        UA_JOBTYPE_METHODCALL, ///< Call the method as soon as possible
+        UA_JOBTYPE_METHODCALL_DELAYED, ///< Call the method as soon as all previous jobs have finished
+    } type;
+    union {
+        UA_Connection *closeConnection;
+        struct {
+            UA_Connection *connection;
+            UA_ByteString message;
+        } binaryMessage;
+        struct {
+            void *data;
+            void (*method)(UA_Server *server, void *data);
+        } methodCall;
+    } job;
+} UA_Job;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* UA_JOB_H_ */

+ 28 - 39
include/ua_server.h

@@ -24,9 +24,10 @@ extern "C" {
 #include "ua_types.h"
 #include "ua_types_generated.h"
 #include "ua_nodeids.h"
-#include "ua_connection.h"
 #include "ua_log.h"
-  
+#include "ua_job.h"
+#include "ua_connection.h"
+
 /**
  * @defgroup server Server
  *
@@ -47,9 +48,6 @@ typedef struct UA_ServerConfig {
 
 extern UA_EXPORT const UA_ServerConfig UA_ServerConfig_standard;
 
-struct UA_Server;
-typedef struct UA_Server UA_Server;
-
 UA_Server UA_EXPORT * UA_Server_new(UA_ServerConfig config);
 void UA_EXPORT UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate);
 void UA_EXPORT UA_Server_delete(UA_Server *server);
@@ -103,7 +101,8 @@ typedef struct {
      * @return Returns a status code for logging. Error codes intended for the original caller are set
      *         in the value. If an error is returned, then no releasing of the value is done.
      */
-    UA_StatusCode (*read)(void *handle, const UA_NodeId nodeid,  UA_Boolean includeSourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value);
+    UA_StatusCode (*read)(void *handle, const UA_NodeId nodeid, UA_Boolean includeSourceTimeStamp,
+                          const UA_NumericRange *range, UA_DataValue *value);
 
     /**
      * Write into a data source. The write member of UA_DataSource can be empty if the operation
@@ -119,6 +118,14 @@ typedef struct {
     UA_StatusCode (*write)(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range);
 } UA_DataSource;
 
+/* Value Callbacks can be attach to value and value type nodes. If not-null, they are called before
+   reading and after writing respectively */
+typedef struct {
+    void *handle;
+    void (*onRead)(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range);
+    void (*onWrite)(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range);
+} UA_ValueCallback;
+
 /** @brief Add a new namespace to the server. Returns the index of the new namespace */
 UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
 
@@ -308,6 +315,10 @@ UA_StatusCode UA_EXPORT
 UA_Server_setNodeAttribute_value_destructive(UA_Server *server, const UA_NodeId nodeId,
                                              const UA_DataType *type, UA_Variant *value);
 
+/* Succeeds only if the node contains a variant value */
+UA_StatusCode UA_EXPORT
+UA_Server_setAttribute_value_callback(UA_Server *server, UA_NodeId nodeId, UA_ValueCallback callback);
+
 UA_StatusCode UA_EXPORT
 UA_Server_setNodeAttribute_value_dataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource dataSource);
 
@@ -456,28 +467,6 @@ UA_StatusCode UA_EXPORT
 UA_Server_getNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId, UA_MethodCallback *method);
 #endif
 
-/** Jobs describe work that is executed once or repeatedly. */
-typedef struct {
-    enum {
-        UA_JOBTYPE_NOTHING,
-        UA_JOBTYPE_DETACHCONNECTION,
-        UA_JOBTYPE_BINARYMESSAGE,
-        UA_JOBTYPE_METHODCALL,
-        UA_JOBTYPE_DELAYEDMETHODCALL,
-    } type;
-    union {
-        UA_Connection *closeConnection;
-        struct {
-            UA_Connection *connection;
-            UA_ByteString message;
-        } binaryMessage;
-        struct {
-            void *data;
-            void (*method)(UA_Server *server, void *data);
-        } methodCall;
-    } job;
-} UA_Job;
-
 /**
  * @param server The server object.
  *
@@ -497,8 +486,8 @@ UA_StatusCode UA_EXPORT UA_Server_addRepeatedJob(UA_Server *server, UA_Job job,
                                                  UA_Guid *jobId);
 
 /**
- * Remove repeated job. The entry will be removed asynchronously during the
- * next iteration of the server main loop.
+ * Remove repeated job. The entry will be removed asynchronously during the next iteration of the
+ * server main loop.
  *
  * @param server The server object.
  *
@@ -516,8 +505,8 @@ UA_StatusCode UA_EXPORT UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid j
  * layer does not need to be thread-safe.
  */
 typedef struct UA_ServerNetworkLayer {
-    void *handle;
     UA_String discoveryUrl;
+    UA_Logger logger; ///< Set during _start
 
     /**
      * Starts listening on the the networklayer.
@@ -526,30 +515,30 @@ typedef struct UA_ServerNetworkLayer {
      * @param logger The logger
      * @return Returns UA_STATUSCODE_GOOD or an error code.
      */
-    UA_StatusCode (*start)(struct UA_ServerNetworkLayer *nl, UA_Logger *logger);
+    UA_StatusCode (*start)(struct UA_ServerNetworkLayer *nl, UA_Logger logger);
     
     /**
      * Gets called from the main server loop and returns the jobs (accumulated messages and close
      * events) for dispatch.
      *
      * @param nl The network layer
-     * @param jobs When the returned integer is positive, *jobs points to an array of UA_Job of the
+     * @param jobs When the returned integer is >0, *jobs points to an array of UA_Job of the
      * returned size.
      * @param timeout The timeout during which an event must arrive in microseconds
      * @return The size of the jobs array. If the result is negative, an error has occurred.
      */
-    UA_Int32 (*getJobs)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout);
+    size_t (*getJobs)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout);
 
     /**
      * Closes the network connection and returns all the jobs that need to be finished before the
      * network layer can be safely deleted.
      *
      * @param nl The network layer
-     * @param jobs When the returned integer is positive, jobs points to an array of UA_Job of the
+     * @param jobs When the returned integer is >0, jobs points to an array of UA_Job of the
      * returned size.
      * @return The size of the jobs array. If the result is negative, an error has occurred.
      */
-    UA_Int32 (*stop)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs);
+    size_t (*stop)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs);
 
     /** Deletes the network layer. Call only after a successful shutdown. */
     void (*deleteMembers)(struct UA_ServerNetworkLayer *nl);
@@ -560,7 +549,7 @@ typedef struct UA_ServerNetworkLayer {
  * with the server. Do not use it after adding it as it might be moved around on
  * the heap.
  */
-void UA_EXPORT UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer);
+void UA_EXPORT UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *networkLayer);
 
 /** @} */
 
@@ -618,8 +607,8 @@ typedef UA_Int32 (*UA_ExternalNodeStore_browseNodes)
  UA_BrowseResult *browseResults, UA_DiagnosticInfo *diagnosticInfos);
 
 typedef UA_Int32 (*UA_ExternalNodeStore_translateBrowsePathsToNodeIds)
-(void *ensHandle, const UA_RequestHeader *requestHeader, UA_BrowsePath *browsePath,
- UA_UInt32 *indices, UA_UInt32 indicesSize, UA_BrowsePathResult *browsePathResults, UA_DiagnosticInfo *diagnosticInfos);
+(void *ensHandle, const UA_RequestHeader *requestHeader, UA_BrowsePath *browsePath, UA_UInt32 *indices,
+ UA_UInt32 indicesSize, UA_BrowsePathResult *browsePathResults, UA_DiagnosticInfo *diagnosticInfos);
 
 typedef UA_Int32 (*UA_ExternalNodeStore_delete)(void *ensHandle);
 

+ 0 - 51
ports/WAGO-750-860.patch

@@ -1,51 +0,0 @@
-From 97515341454f26fcd14e50d5980f5f0361307814 Mon Sep 17 00:00:00 2001
-From: FlorianPalm <f.palm@plt.rwth-aachen.de>
-Date: Mon, 12 Jan 2015 18:45:01 +0100
-Subject: [PATCH] fixes to the patch
-
----
- CMakeLists.txt | 19 ++++++++-----------
- src/ua_util.h  |  2 +-
- 2 files changed, 9 insertions(+), 12 deletions(-)
-
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index c785182..9e66da0 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -47,19 +47,16 @@ set(lib_sources src/ua_types.c
- 
- # compiler flags
- if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
--add_definitions(-std=c99 -pipe -Wall -Wextra -Werror -Wformat
--                -Wno-unused-parameter -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare -Wmultichar
--                -Wshadow -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes # -Wconversion
--                -Winit-self -Wuninitialized -Wno-deprecated -Wformat-security -ffunction-sections -fdata-sections)
-+add_definitions(-std=c99 -fomit-frame-pointer -pipe -msoft-float -fno-builtin -DEMBED -fno-strict-aliasing)
-     if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
-         add_definitions(-Wformat-nonliteral)
--        set (CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--gc-sections")
--        set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
-+        set (CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-elf2flt -msoft-float")
-+        set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}  -Wl,-elf2flt -msoft-float")
-     else()
-         add_definitions(-Wno-gnu-statement-expression)
-     endif()
- 	if(NOT WIN32)
--	    add_definitions(-fstack-protector -fPIC -fvisibility=hidden)
-+	   # add_definitions(-fPIC)
- 	endif()
- endif()
- 
-@@ -90,11 +90,7 @@ else()
- endif()
- 
- add_library(open62541-objects OBJECT ${lib_sources})
--add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-objects>)
--add_library(open62541-static STATIC $<TARGET_OBJECTS:open62541-objects>)
--SET_TARGET_PROPERTIES(open62541-static PROPERTIES OUTPUT_NAME open62541 CLEAN_DIRECT_OUTPUT 1) # static version that exports all symbols
--target_compile_definitions(open62541-objects PRIVATE UA_DYNAMIC_LINKING)
--target_compile_definitions(open62541-static PRIVATE UA_DYNAMIC_LINKING)
-+add_library(open62541 $<TARGET_OBJECTS:open62541-objects>)
- 
- ## logging
- set(UA_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported")

+ 17 - 18
src/client/ua_client.c

@@ -113,7 +113,7 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
     hello.sendBufferSize = conn->localConf.sendBufferSize;
 
     UA_ByteString message;
-    UA_StatusCode retval = c->connection.getBuffer(&c->connection, &message);
+    UA_StatusCode retval = c->connection.getSendBuffer(&c->connection, c->connection.remoteConf.recvBufferSize, &message);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
@@ -124,15 +124,14 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
     retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &message, &offset);
     UA_TcpHelloMessage_deleteMembers(&hello);
     if(retval != UA_STATUSCODE_GOOD) {
-        c->connection.releaseBuffer(&c->connection, &message);
+        c->connection.releaseSendBuffer(&c->connection, &message);
         return retval;
     }
 
-    retval = c->connection.write(&c->connection, &message, messageHeader.messageSize);
-    if(retval != UA_STATUSCODE_GOOD) {
-        c->connection.releaseBuffer(&c->connection, &message);
+    message.length = messageHeader.messageSize;
+    retval = c->connection.send(&c->connection, &message);
+    if(retval != UA_STATUSCODE_GOOD)
         return retval;
-    }
 
     UA_ByteString reply;
     UA_ByteString_init(&reply);
@@ -194,7 +193,8 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     }
 
     UA_ByteString message;
-    UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message);
+    UA_Connection *c = &client->connection;
+    UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
@@ -213,15 +213,14 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
     UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
     if(retval != UA_STATUSCODE_GOOD) {
-        client->connection.releaseBuffer(&client->connection, &message);
+        client->connection.releaseSendBuffer(&client->connection, &message);
         return retval;
     }
 
-    retval = client->connection.write(&client->connection, &message, messageHeader.messageHeader.messageSize);
-    if(retval != UA_STATUSCODE_GOOD) {
-        client->connection.releaseBuffer(&client->connection, &message);
+    message.length = messageHeader.messageHeader.messageSize;
+    retval = client->connection.send(&client->connection, &message);
+    if(retval != UA_STATUSCODE_GOOD)
         return retval;
-    }
 
     UA_ByteString reply;
     UA_ByteString_init(&reply);
@@ -508,7 +507,8 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
     UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CLOSESECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
 
     UA_ByteString message;
-    UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message);
+    UA_Connection *c = &client->connection;
+    UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
@@ -523,13 +523,12 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
     retval |= UA_SecureConversationMessageHeader_encodeBinary(&msgHeader, &message, &offset);
 
     if(retval != UA_STATUSCODE_GOOD) {
-        client->connection.releaseBuffer(&client->connection, &message);
+        client->connection.releaseSendBuffer(&client->connection, &message);
         return retval;
     }
         
-    retval = client->connection.write(&client->connection, &message, msgHeader.messageHeader.messageSize);
-    if(retval != UA_STATUSCODE_GOOD)
-        client->connection.releaseBuffer(&client->connection, &message);
+    message.length = msgHeader.messageHeader.messageSize;
+    retval = client->connection.send(&client->connection, &message);
     return retval;
 }
 
@@ -548,7 +547,7 @@ UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection co
         UA_Client_reset(client);
     }
 
-    client->connection = connectFunc(UA_ConnectionConfig_standard, endpointUrl, &client->logger);
+    client->connection = connectFunc(UA_ConnectionConfig_standard, endpointUrl, client->logger);
     if(client->connection.state != UA_CONNECTION_OPENING){
         retval = UA_STATUSCODE_BADCONNECTIONCLOSED;
         goto cleanup;

+ 0 - 281
src/ongoing/generateSam.c

@@ -1,281 +0,0 @@
-#include "ua_xml.h"
-#include "ua_namespace.h"
-#include "ua_namespace_xml.h"
-#include "ua_types_generated.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}",node->nodeId.identifier.numeric));
-	// 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 = node->references[i].referenceTypeId.identifier.numeric;
-		UA_Int32 isInverse = node->references[i].isInverse;
-		if (isInverse && (refId == 47 || refId == 46)) {
-			UA_Int32 retval = Namespace_get(theNamespace, &(node->references[i].targetId.nodeId),parent);
-			if (retval == UA_SUCCESS) {
-				DBG(printf(" has parent={i=%d}\n",(*parent)->nodeId.identifier.numeric));
-			} else {
-				DBG(printf(" has non-existing parent={i=%d}\n", node->references[i].targetId.nodeId.identifier.numeric));
-			}
-			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",node->nodeId.identifier.numeric,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",node->nodeId.identifier.numeric,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_.types[UA_ns0ToVTableIndex(&vn->nodeId)].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_.types[UA_ns0ToVTableIndex(&vn->dataType)].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_SUCCESS)
-		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++;
-		}
-	}
-	Namespace_releaseManagedNode(node);
-	*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_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);
-				Namespace_releaseManagedNode(node);
-				return retval;
-			}
-		}
-	}
-	Namespace_releaseManagedNode(node);
-	return UA_ERR_INVALID_VALUE;
-}
-
-
-UA_Int32 UAX_NodeId_encodeBinaryByMetaData(Namespace const * ns, UA_NodeId const * id, UA_UInt32* pos, UA_ByteString *dst) {
-	UA_Int32 i, retval = UA_SUCCESS;
-	if (UA_NodeId_isBasicType(id)) {
-		const UA_Node * result;
-		if ((retval = Namespace_get(ns,id,&result)) == UA_SUCCESS) {
-			UA_Variant_encodeBinary(&((UA_VariableNode *) result)->value,dst,pos);
-			Namespace_releaseManagedNode(result);
-		}
-	} 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_ByteString *dst, UA_UInt32* offset) {
-	UA_Int32 retval = UA_SUCCESS;
-	UA_Node const * node;
-	if ((retval = Namespace_get(ns,id,&node)) == UA_SUCCESS) {
-		if (node->nodeClass == UA_NODECLASS_VARIABLE) {
-			retval = UA_Variant_encodeBinary(&((UA_VariableNode*) node)->value,dst,offset);
-		}
-		Namespace_releaseManagedNode(node);
-	}
-	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 - 85
src/ongoing/ua_namespace_xml.c

@@ -1,85 +0,0 @@
-#include "ua_namespace_xml.h"
-#include <fcntl.h> // open, O_RDONLY
-
-typedef UA_Int32 (*XML_Stack_Loader) (char* buf, int len);
-
-#define XML_BUFFER_LEN 1024
-UA_Int32 Namespace_loadXml(Namespace **ns,UA_UInt32 nsid,const char* rootName, XML_Stack_Loader getNextBufferFull) {
-	UA_Int32 retval = UA_SUCCESS;
-	char buf[XML_BUFFER_LEN];
-	int len; /* len is the number of bytes in the current bufferful of data */
-
-	XML_Stack s;
-	XML_Stack_init(&s, 0, rootName);
-
-	UA_NodeSet n;
-	UA_NodeSet_init(&n, 0);
-	*ns = n.ns;
-
-	XML_Stack_addChildHandler(&s, "UANodeSet", strlen("UANodeSet"), (XML_decoder) UA_NodeSet_decodeXmlFromStack, UA_INVALIDTYPE, &n);
-	XML_Parser parser = XML_ParserCreate(UA_NULL);
-	XML_SetUserData(parser, &s);
-	XML_SetElementHandler(parser, XML_Stack_startElement, XML_Stack_endElement);
-	XML_SetCharacterDataHandler(parser, XML_Stack_handleText);
-	while ((len = getNextBufferFull(buf, XML_BUFFER_LEN)) > 0) {
-		if (XML_Parse(parser, buf, len, (len < XML_BUFFER_LEN)) == XML_STATUS_ERROR) {
-			retval = UA_ERR_INVALID_VALUE;
-			break;
-		}
-	}
-	XML_ParserFree(parser);
-
-	DBG_VERBOSE(printf("Namespace_loadXml - aliases addr=%p, size=%d\n", (void*) &(n.aliases), n.aliases.size));
-	DBG_VERBOSE(UA_NodeSetAliases_println("Namespace_loadXml - elements=", &n.aliases));
-
-	return retval;
-}
-
-static int theFile = 0;
-UA_Int32 readFromTheFile(char*buf,int len) {
-	return read(theFile,buf,len);
-}
-
-/** @brief load a namespace from an XML-File
- *
- * @param[in/out] ns the address of the namespace ptr
- * @param[in] namespaceIndex 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 nsid,const char* rootName,const char* fileName) {
-	if (fileName == UA_NULL)
-		theFile = 0; // stdin
-	else if ((theFile = open(fileName, O_RDONLY)) == -1)
-		return UA_ERR_INVALID_VALUE;
-
-	UA_Int32 retval = Namespace_loadXml(ns,nsid,rootName,readFromTheFile);
-	close(theFile);
-	return retval;
-}
-
-static const char* theBuffer = UA_NULL;
-static const char* theBufferEnd = UA_NULL;
-UA_Int32 readFromTheBuffer(char*buf,int len) {
-	if (len == 0) return 0;
-	if (theBuffer + XML_BUFFER_LEN > theBufferEnd)
-		len = theBufferEnd - theBuffer + 1;
-	else
-		len = XML_BUFFER_LEN;
-	memcpy(buf,theBuffer,len);
-	theBuffer = theBuffer + len;
-	return len;
-}
-
-/** @brief load a namespace from a string
- *
- * @param[in/out] ns the address of the namespace ptr
- * @param[in] namespaceIndex the numeric id of the namespace
- * @param[in] rootName the name of the root element of the hierarchy (not used?)
- * @param[in] buffer the xml string
- */
-UA_Int32 Namespace_loadFromString(Namespace **ns,UA_UInt32 nsid,const char* rootName,const char* buffer) {
-	theBuffer = buffer;
-	theBufferEnd = buffer + strlen(buffer) - 1;
-	return Namespace_loadXml(ns,nsid,rootName,readFromTheBuffer);
-}

+ 0 - 41
src/ongoing/ua_namespace_xml.h

@@ -1,41 +0,0 @@
-#ifndef __UA_NAMESPACE_XML_H
-#define __UA_NAMESPACE_XML_H
-
-#include "ua_xml.h"
-#include "ua_types_generated.h"
-#include "ua_namespace.h"
-
-void print_node(UA_Node const * node);
-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_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_NodeSet* dst, _Bool isStart);
-
-UA_Int32 UA_ExpandedNodeId_copycstring(cstring src, UA_ExpandedNodeId* dst, UA_NodeSetAliases* aliases);
-
-/** @brief load a namespace from an XML-File
- *
- * @param[in/out] ns the address of the namespace ptr
- * @param[in] namespaceIndex 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 namespaceIndex,const char* rootName,const char* fileName);
-UA_Int32 Namespace_loadFromString(Namespace **ns,UA_UInt32 nsid,const char* rootName,const char* buffer);
-
-#endif /* __UA_NAMESPACE_XML_H */

+ 0 - 447
src/ongoing/ua_types_encoding_xml.c

@@ -1,447 +0,0 @@
-#include "ua_types_encoding_xml.h"
-#include "ua_util.h"
-#include "ua_namespace_0.h"
-#include "ua_xml.h"
-
-/* Boolean */
-
-UA_Int32 UA_Boolean_copycstring(cstring src, UA_Boolean *dst) {
-	*dst = UA_FALSE;
-	if(0 == strncmp(src, "true", 4) || 0 == strncmp(src, "TRUE", 4))
-		*dst = UA_TRUE;
-	return UA_SUCCESS;
-}
-
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_Boolean)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_Boolean)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Boolean)
-/* UA_Int32 UA_Boolean_decodeXML(XML_Stack *s, XML_Attr *attr, UA_Boolean *dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_Boolean entered with dst=%p,isStart=%d\n", (void * )dst, isStart)); */
-/* 	if(isStart) { */
-/* 		if(dst == UA_NULL) { */
-/* 			UA_Boolean_new(&dst); */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst; */
-/* 		} */
-/* 		UA_Boolean_copycstring((cstring)attr[1], dst); */
-/* 	} */
-/* 	return UA_SUCCESS; */
-/* } */
-
-/* SByte */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_SByte)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_SByte)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_SByte)
-
-/* Byte */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_Byte)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_Byte)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Byte)
-
-/* Int16 */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_Int16)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_Int16)
-
-UA_Int32 UA_Int16_copycstring(cstring src, UA_Int16 *dst) {
-	*dst = atoi(src);
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_UInt16_copycstring(cstring src, UA_UInt16 *dst) {
-	*dst = atoi(src);
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_Int16_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_Int16 *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_Int32 entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_Int16_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		UA_Int16_copycstring((cstring)attr[1], dst);
-	}
-	return UA_SUCCESS;
-}
-
-UA_TYPE_DECODEXML_FROM_BYTESTRING(UA_Int16)
-
-/* UInt16 */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_UInt16)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_UInt16)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_UInt16)
-
-/* Int32 */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_Int32)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_Int32)
-
-UA_Int32 UA_Int32_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_Int32 *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_Int32 entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_Int32_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		*dst = atoi(attr[1]);
-	}
-	return UA_SUCCESS;
-}
-UA_TYPE_DECODEXML_FROM_BYTESTRING(UA_Int32)
-
-/* UInt32 */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_UInt32)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_UInt32)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_UInt32)
-
-/* Int64 */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_Int64)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_Int64)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Int64)
-
-/* UInt64 */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_UInt64)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_UInt64)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_UInt64)
-
-/* Float */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_Float)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_Float)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Float)
-
-/* Double */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_Double)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_Double)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Double)
-
-/* String */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_String)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_String)
-
-UA_Int32 UA_String_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_String *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_String entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	UA_UInt32 i;
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_String_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "Data", strlen("Data"), (XML_decoder)UA_Text_decodeXmlFromStack, UA_BYTE,
-		                          &(dst->data));
-		XML_Stack_addChildHandler(s, "Length", strlen("Length"), (XML_decoder)UA_Int32_decodeXmlFromStack, UA_INT32,
-		                          &(dst->length));
-		XML_Stack_handleTextAsElementOf(s, "Data", 0);
-
-		// set attributes
-		for(i = 0;attr[i];i += 2) {
-			if(0 == strncmp("Data", attr[i], strlen("Data")))
-				UA_String_copycstring(attr[i + 1], dst);
-			else
-				printf("UA_String_decodeXml - Unknown attribute - name=%s, value=%s\n", attr[i], attr[i+1]);
-		}
-	} else {
-		switch(s->parent[s->depth - 1].activeChild) {
-		case 0:
-			if(dst != UA_NULL && dst->data != UA_NULL && dst->length == -1)
-				dst->length = strlen((char const *)dst->data);
-			break;
-		}
-	}
-	return UA_SUCCESS;
-}
-
-UA_TYPE_DECODEXML_FROM_BYTESTRING(UA_String)
-
-/* DateTime */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_DateTime)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_DateTime)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_DateTime)
-
-/* Guid */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_Guid)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_Guid)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_Guid)
-
-/* ByteString */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_ByteString)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_ByteString)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_ByteString)
-
-/* XmlElement */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_XmlElement)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_XmlElement)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_XmlElement)
-
-/* NodeId */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_NodeId)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_NodeId)
-
-UA_Int32 UA_NodeId_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_NodeId *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_NodeId entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	UA_UInt32 i;
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_NodeId_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "Namespace", strlen(
-		                              "Namespace"), (XML_decoder)UA_Int16_decodeXmlFromStack, UA_INT16,
-		                          &(dst->namespaceIndex));
-		XML_Stack_addChildHandler(s, "Numeric", strlen(
-		                              "Numeric"), (XML_decoder)UA_Int32_decodeXmlFromStack, UA_INT32,
-		                          &(dst->identifier.numeric));
-		XML_Stack_addChildHandler(s, "Identifier", strlen(
-		                              "Identifier"), (XML_decoder)UA_String_decodeXmlFromStack, UA_STRING, UA_NULL);
-		XML_Stack_handleTextAsElementOf(s, "Data", 2);
-
-		// set attributes
-		for(i = 0; attr[i]; i += 2) {
-		if(0 == strncmp("Namespace", attr[i], strlen("Namespace")))
-			dst->namespaceIndex = atoi(attr[i + 1]);
-		else if(0 == strncmp("Numeric", attr[i], strlen("Numeric"))) {
-			dst->identifierType = UA_NODEIDTYPE_NUMERIC;
-			dst->identifier.numeric = atoi(attr[i + 1]);
-		} else
-			printf("UA_NodeId_decodeXml - Unknown attribute name=%s, value=%s\n", attr[i], attr[i+1]);
-		}
-	} else {
-		if(s->parent[s->depth - 1].activeChild == 2)
-			UA_NodeId_copycstring((cstring)((UA_String *)attr)->data, dst, s->aliases);
-	}
-	return UA_SUCCESS;
-}
-
-UA_TYPE_DECODEXML_FROM_BYTESTRING(UA_NodeId)
-
-/* ExpandedNodeId */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_ExpandedNodeId)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_ExpandedNodeId)
-
-UA_Int32 UA_ExpandedNodeId_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_ExpandedNodeId *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_ExpandedNodeId entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	UA_UInt32 i;
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_ExpandedNodeId_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "NodeId", strlen(
-		                              "NodeId"), (XML_decoder)UA_NodeId_decodeXmlFromStack, UA_NODEID, &(dst->nodeId));
-		XML_Stack_addChildHandler(s, "Namespace", strlen("Namespace"),
-								  (XML_decoder)UA_Int16_decodeXmlFromStack, UA_INT16,
-		                          &(dst->nodeId.namespaceIndex));
-		XML_Stack_addChildHandler(s, "Numeric", strlen("Numeric"), (XML_decoder)UA_Int32_decodeXmlFromStack, UA_INT32,
-		                          &(dst->nodeId.identifier.numeric));
-		XML_Stack_addChildHandler(s, "Id", strlen("Id"), (XML_decoder)UA_String_decodeXmlFromStack, UA_STRING, UA_NULL);
-		XML_Stack_handleTextAsElementOf(s, "Data", 3);
-
-		// set attributes
-		for(i = 0; attr[i]; i += 2) {
-		if(0 == strncmp("Namespace", attr[i], strlen("Namespace")))
-			UA_UInt16_copycstring((cstring)attr[i + 1], &(dst->nodeId.namespaceIndex));
-		else if(0 == strncmp("Numeric", attr[i], strlen("Numeric"))) {
-		UA_NodeId_copycstring((cstring)attr[i + 1], &(dst->nodeId), s->aliases);
-		} else if(0 == strncmp("NodeId", attr[i], strlen("NodeId")))
-			UA_NodeId_copycstring((cstring)attr[i + 1], &(dst->nodeId), s->aliases);
-		else
-			printf("UA_ExpandedNodeId_decodeXml - unknown attribute name=%s, value=%s\n", attr[i], attr[i+1]);
-		}
-	}
-	return UA_SUCCESS;
-}
-
-UA_TYPE_DECODEXML_FROM_BYTESTRING(UA_ExpandedNodeId)
-
-/* StatusCode */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_StatusCode)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_StatusCode)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_StatusCode)
-/* UA_Int32 UA_StatusCode_decodeXML(XML_Stack *s, XML_Attr *attr, UA_StatusCode *dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_StatusCode_decodeXML entered with dst=%p,isStart=%d\n", (void * )dst, isStart)); */
-/* 	return UA_ERR_NOT_IMPLEMENTED; */
-/* } */
-
-/* QualifiedName */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_QualifiedName)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_QualifiedName)
-
-UA_Int32 UA_QualifiedName_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_QualifiedName *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_QualifiedName entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	UA_UInt32 i;
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_QualifiedName_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "Name", strlen("Name"), (XML_decoder)UA_String_decodeXmlFromStack, UA_STRING,
-		                          &(dst->name));
-		XML_Stack_addChildHandler(s, "NamespaceIndex", strlen(
-		                              "NamespaceIndex"), (XML_decoder)UA_Int16_decodeXmlFromStack, UA_STRING,
-		                          &(dst->namespaceIndex));
-		XML_Stack_handleTextAsElementOf(s, "Data", 0);
-
-		// set attributes
-		for(i = 0;attr[i];i += 2) {
-			if(0 == strncmp("NamespaceIndex", attr[i], strlen("NamespaceIndex")))
-				dst->namespaceIndex = atoi(attr[i + 1]);
-			else if(0 == strncmp("Name", attr[i], strlen("Name")))
-				UA_String_copycstring(attr[i + 1], &(dst->name));
-			else
-				perror("Unknown attribute");
-		}
-	}
-	return UA_SUCCESS;
-}
-
-UA_TYPE_DECODEXML_FROM_BYTESTRING(UA_QualifiedName)
-
-/* LocalizedText */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_LocalizedText)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_LocalizedText)
-
-UA_Int32 UA_LocalizedText_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_LocalizedText *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_LocalizedText entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	UA_UInt32 i;
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_LocalizedText_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		// s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "Text", strlen("Text"), (XML_decoder)UA_String_decodeXmlFromStack, UA_STRING,
-		                          &(dst->text));
-		XML_Stack_addChildHandler(s, "Locale", strlen(
-		                              "Locale"), (XML_decoder)UA_String_decodeXmlFromStack, UA_STRING, &(dst->locale));
-		XML_Stack_handleTextAsElementOf(s, "Data", 0);
-
-		// set attributes
-		for(i = 0;attr[i];i += 2) {
-			if(0 == strncmp("Text", attr[i], strlen("Text"))) {
-				UA_String_copycstring(attr[i + 1], &dst->text);
-			} else if(0 == strncmp("Locale", attr[i], strlen("Locale"))) {
-				UA_String_copycstring(attr[i + 1], &dst->locale);
-			} else
-				perror("Unknown attribute");
-		}
-	} else {
-		switch(s->parent[s->depth - 1].activeChild) {
-		case 0:
-			//dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
-			break;
-
-		case 1:
-			//dst->encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
-			break;
-
-		default:
-			break;
-		}
-	}
-	return UA_SUCCESS;
-}
-
-UA_TYPE_DECODEXML_FROM_BYTESTRING(UA_LocalizedText)
-
-/* ExtensionObject */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_ExtensionObject)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_ExtensionObject)
-
-UA_Int32 UA_ExtensionObject_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_ExtensionObject *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_ExtensionObject entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	UA_UInt32 i;
-
-	if(isStart) {
-		// create a new object if called with UA_NULL
-		if(dst == UA_NULL) {
-			UA_ExtensionObject_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-
-		s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "TypeId", strlen(
-		                              "TypeId"), (XML_decoder)UA_NodeId_decodeXmlFromStack, UA_NODEID, &(dst->typeId));
-		// XML_Stack_addChildHandler(s, "Body", strlen("Body"), (XML_decoder) UA_Body_decodeXml, UA_LOCALIZEDTEXT, UA_NULL);
-
-		// set attributes
-		for(i = 0;attr[i];i += 2) {
-			{
-				DBG_ERR(XML_Stack_print(s));
-				DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
-			}
-		}
-	}
-	return UA_SUCCESS;
-}
-
-UA_TYPE_DECODEXML_FROM_BYTESTRING(UA_ExtensionObject)
-
-/* DataValue */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_DataValue)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_DataValue)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_DataValue)
-
-/* Variant */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_Variant)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_Variant)
-
-UA_Int32 UA_Variant_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_Variant *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_Variant entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	UA_UInt32 i;
-
-	if(isStart) {
-		// create a new object if called with UA_NULL
-		if(dst == UA_NULL) {
-			UA_Variant_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-
-		s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "ListOfExtensionObject", strlen(
-		                              "ListOfExtensionObject"), (XML_decoder)UA_TypedArray_decodeXmlFromStack,
-		                          UA_EXTENSIONOBJECT, UA_NULL);
-		XML_Stack_addChildHandler(s, "ListOfLocalizedText", strlen(
-		                              "ListOfLocalizedText"), (XML_decoder)UA_TypedArray_decodeXmlFromStack,
-		                          UA_LOCALIZEDTEXT, UA_NULL);
-
-		// set attributes
-		for(i = 0;attr[i];i += 2) {
-			{
-				DBG_ERR(XML_Stack_print(s));
-				DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
-			}
-		}
-	} else {
-		if(s->parent[s->depth - 1].activeChild == 0 && attr != UA_NULL ) {  // ExtensionObject
-			UA_TypedArray *array = (UA_TypedArray *)attr;
-			DBG_VERBOSE(printf("UA_Variant_decodeXml - finished array: references=%p, size=%d\n", (void *)array,
-			                   (array == UA_NULL) ? -1 : array->size));
-			dst->arrayLength  = array->size;
-			dst->data         = array->elements;
-			dst->vt = &UA_.types[UA_EXTENSIONOBJECT];
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
-		} else if(s->parent[s->depth - 1].activeChild == 1 && attr != UA_NULL ) {  // LocalizedText
-			UA_TypedArray *array = (UA_TypedArray *)attr;
-			DBG_VERBOSE(printf("UA_Variant_decodeXml - finished array: references=%p, size=%d\n", (void *)array,
-			                   (array == UA_NULL) ? -1 : array->size));
-			dst->arrayLength  = array->size;
-			dst->data         = array->elements;
-			dst->vt = &UA_.types[UA_LOCALIZEDTEXT];
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
-		}
-	}
-	return UA_SUCCESS;
-}
-
-UA_TYPE_DECODEXML_FROM_BYTESTRING(UA_Variant)
-
-/* DiagnosticInfo */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_DiagnosticInfo)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_DiagnosticInfo)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_DiagnosticInfo)
-
-/* InvalidType */
-UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(UA_InvalidType)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(UA_InvalidType)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(UA_InvalidType)

+ 0 - 77
src/ongoing/ua_types_encoding_xml.h

@@ -1,77 +0,0 @@
-#ifndef UA_TYPES_ENCODING_XML_H_
-#define UA_TYPES_ENCODING_XML_H_
-
-#include "ua_xml.h"
-#include "ua_types.h"
-
-#define UA_TYPE_XML_ENCODING(TYPE)							\
-	UA_Int32 TYPE##_calcSizeXml(const void * p); \
-    UA_Int32 TYPE##_encodeXml(const TYPE *src, UA_ByteString *dst, UA_UInt32 *offset); \
-	UA_Int32 TYPE##_decodeXml(UA_ByteString *src, UA_UInt32 *offset, TYPE *dst); \
-	UA_Int32 TYPE##_encodeXmlToStack(const TYPE *src, XML_Stack *s, XML_Attr *attr); \
-	UA_Int32 TYPE##_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, TYPE* dst, UA_Boolean isStart);
-
-#define UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(TYPE) \
-	UA_Int32 TYPE##_calcSizeXml(const void * p) { \
-	return -1; \
- }
-
-#define UA_TYPE_METHOD_ENCODEXML_NOTIMPL(TYPE) \
-    UA_Int32 TYPE##_encodeXml(const TYPE *src, UA_ByteString *dst, UA_UInt32 *offset) { \
-        return UA_ERR_NOT_IMPLEMENTED; \
-	}																	\
-	UA_Int32 TYPE##_encodeXmlToStack(const TYPE *src, XML_Stack *s, XML_Attr *attr) { \
-																					 DBG_VERBOSE(printf(#TYPE "_encodeXML entered with src=%p\n", (void* ) src)); \
-     return UA_ERR_NOT_IMPLEMENTED;\
- }
-
-#define UA_TYPE_METHOD_DECODEXML_NOTIMPL(TYPE) \
-	UA_Int32 TYPE##_decodeXml(UA_ByteString *src, UA_UInt32 *offset, TYPE *dst) { \
-        return UA_ERR_NOT_IMPLEMENTED;									\
-	}																	\
-																		\
- UA_Int32 TYPE##_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, TYPE* dst, UA_Boolean isStart) { \
-																								  DBG_VERBOSE(printf(#TYPE "_decodeXML entered with dst=%p,isStart=%d\n", (void* ) dst, (_Bool) isStart)); \
-     return UA_ERR_NOT_IMPLEMENTED; \
- }
-
-#define UA_TYPE_DECODEXML_FROM_BYTESTRING(TYPE) \
-	UA_Int32 TYPE##_decodeXml(UA_ByteString *src, UA_UInt32 *offset, TYPE *dst) { \
-	/* // Init Stack here \
-	UA_Stack *stack; \
-	UA_Attr *attr; \
-	TYPE##decodeXmlFromStack(stack, attr, dst, UA_TRUE); \
-	*/ \
-	return UA_ERR_NOT_IMPLEMENTED; \
-} 
-
-UA_TYPE_XML_ENCODING(UA_Boolean)
-UA_TYPE_XML_ENCODING(UA_SByte)
-UA_TYPE_XML_ENCODING(UA_Byte)
-UA_TYPE_XML_ENCODING(UA_Int16)
-UA_TYPE_XML_ENCODING(UA_UInt16)
-UA_TYPE_XML_ENCODING(UA_Int32)
-UA_TYPE_XML_ENCODING(UA_UInt32)
-UA_TYPE_XML_ENCODING(UA_Int64)
-UA_TYPE_XML_ENCODING(UA_UInt64)
-UA_TYPE_XML_ENCODING(UA_Float)
-UA_TYPE_XML_ENCODING(UA_Double)
-UA_TYPE_XML_ENCODING(UA_String)
-UA_TYPE_XML_ENCODING(UA_DateTime)
-UA_TYPE_XML_ENCODING(UA_Guid)
-UA_TYPE_XML_ENCODING(UA_ByteString)
-UA_TYPE_XML_ENCODING(UA_XmlElement)
-UA_TYPE_XML_ENCODING(UA_NodeId)
-UA_TYPE_XML_ENCODING(UA_ExpandedNodeId)
-UA_TYPE_XML_ENCODING(UA_StatusCode)
-UA_TYPE_XML_ENCODING(UA_QualifiedName)
-UA_TYPE_XML_ENCODING(UA_LocalizedText)
-UA_TYPE_XML_ENCODING(UA_ExtensionObject)
-UA_TYPE_XML_ENCODING(UA_DataValue)
-UA_TYPE_XML_ENCODING(UA_Variant)
-UA_TYPE_XML_ENCODING(UA_DiagnosticInfo)
-
-/* Not built-in types */
-UA_TYPE_XML_ENCODING(UA_InvalidType)
-
-#endif /* UA_TYPES_ENCODING_XML_H_ */

+ 0 - 980
src/ongoing/ua_xml.c

@@ -1,980 +0,0 @@
-#include "ua_types_generated.h"
-#include "ua_types_encoding_xml.h"
-#include "ua_xml.h"
-#include "ua_namespace_xml.h"
-#include <fcntl.h> // open, O_RDONLY
-
-UA_Int32 UA_TypedArray_init(UA_TypedArray *p) {
-	p->size     = -1;
-	p->vt       = &UA_.types[UA_INVALIDTYPE];
-	p->elements = UA_NULL;
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_TypedArray_new(UA_TypedArray **p) {
-	UA_alloc((void ** )p, sizeof(UA_TypedArray));
-	UA_TypedArray_init(*p);
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_TypedArray_setType(UA_TypedArray *p, UA_Int32 type) {
-	UA_Int32 retval = UA_ERR_INVALID_VALUE;
-	if(type >= UA_BOOLEAN && type <= UA_INVALIDTYPE) {
-		p->vt  = &UA_.types[type];
-		retval = UA_SUCCESS;
-	}
-	return retval;
-}
-
-// FIXME: We might want to have these classes and their methods
-// defined in opcua.h via generate_builtin and the plugin-concept
-// or in ua_basictypes.c
-
-UA_Int32 UA_NodeSetAlias_init(UA_NodeSetAlias *p) {
-	UA_String_init(&(p->alias));
-	UA_String_init(&(p->value));
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_NodeSetAlias_new(UA_NodeSetAlias **p) {
-	UA_alloc((void ** )p, sizeof(UA_NodeSetAlias));
-	UA_NodeSetAlias_init(*p);
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_NodeSetAliases_init(UA_NodeSetAliases *p) {
-	p->size    = -1;
-	p->aliases = UA_NULL;
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_NodeSetAliases_new(UA_NodeSetAliases **p) {
-	UA_alloc((void ** )p, sizeof(UA_NodeSetAliases));
-	UA_NodeSetAliases_init(*p);
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_NodeSetAliases_println(cstring label, UA_NodeSetAliases *p) {
-	UA_Int32 i;
-	for(i = 0;i < p->size;i++) {
-		UA_NodeSetAlias *a = p->aliases[i];
-		printf("%s{addr=%p", label, (void *)a);
-		if(a)
-			printf(",alias='%.*s', value='%.*s'", a->alias.length, a->alias.data, a->value.length, a->value.data);
-		printf("}\n");
-	}
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_NodeSet_init(UA_NodeSet *p, UA_UInt32 nsid) {
-	Namespace_new(&p->ns, nsid);
-	p->aliases.size    = -1;
-	p->aliases.aliases = UA_NULL;
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_NodeSet_new(UA_NodeSet **p, UA_UInt32 nsid) {
-	UA_alloc((void ** )p, sizeof(UA_NodeSet));
-	UA_NodeSet_init(*p, nsid);
-	return UA_SUCCESS;
-}
-
-UA_Int32 _UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases) {
-	UA_Int32 retval = UA_SUCCESS;
-	if (src != UA_NULL && dst != UA_NULL ) {
-		if (src[0] == 'i' && src[1] == '=') { // namespace zero numeric identifier
-			dst->identifier.numeric = atoi(&src[2]);
-		} else if (src[0] == 'n' && src[1] == 's' && src[2] == '=') { // namespace
-			dst->namespaceIndex = atoi(&src[3]);
-			src = strchr(&src[3],';');
-			if (src != UA_NULL)
-				retval = _UA_NodeId_copycstring(src+1,dst,aliases);  // +1 to start beyond ;
-			else
-				retval = UA_ERR_INVALID_VALUE;
-		} else if (aliases != UA_NULL ) { // try for aliases
-			UA_Int32 i;
-			for (i = 0; i < aliases->size && dst->identifier.numeric == 0; ++i) {
-				if (0 == strncmp((char const*) src, (char const*) aliases->aliases[i]->alias.data,
-								aliases->aliases[i]->alias.length)) {
-					_UA_NodeId_copycstring((cstring)aliases->aliases[i]->alias.data,dst,UA_NULL); // substitute text of alias
-				}
-			}
-		} else {
-			retval = UA_ERR_NOT_IMPLEMENTED;
-		}
-	} else {
-		retval = UA_ERR_INVALID_VALUE;
-	}
-	DBG_VERBOSE(printf("UA_NodeId_copycstring src=%s,id=%d\n", src, dst->identifier.numeric));
-	return retval;
-}
-
-UA_Int32 UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases) {
-	dst->identifierType = UA_NODEIDTYPE_NUMERIC;
-	dst->namespaceIndex = 0;
-	dst->identifier.numeric = 0;
-	return _UA_NodeId_copycstring(src,dst,aliases);
-}
-
-UA_Int32 UA_ReferenceNode_println(cstring label, UA_ReferenceNode *a) {
-	printf("%s{referenceType=%d, target=%d, isInverse=%d}\n",
-	       label,
-	       a->referenceTypeId.identifier.numeric,
-	       a->targetId.nodeId.identifier.numeric,
-	       a->isInverse);
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_ExpandedNodeId_copycstring(cstring src, UA_ExpandedNodeId *dst, UA_NodeSetAliases *aliases) {
-	dst->nodeId.namespaceIndex     = 0;
-	dst->nodeId.identifierType     = UA_NODEIDTYPE_NUMERIC;
-	dst->nodeId.identifier.numeric = 0;
-	UA_NodeId_copycstring(src, &(dst->nodeId), aliases);
-	DBG_VERBOSE(printf("UA_ExpandedNodeId_copycstring src=%s,id=%d\n", src, dst->nodeId.identifier.numeric));
-	return UA_SUCCESS;
-}
-
-void XML_Stack_init(XML_Stack* p, UA_UInt32 nsid, cstring name) {
-	unsigned int i, j;
-	p->depth = 0;
-	for(i = 0;i < XML_STACK_MAX_DEPTH;i++) {
-		p->parent[i].name = UA_NULL;
-		p->parent[i].len  = 0;
-		p->parent[i].activeChild   = -1;
-		p->parent[i].textAttrib    = UA_NULL;
-		p->parent[i].textAttribIdx = -1;
-		/* p->parent[i].totalGatherLength = -1; */
-		/* UA_list_init(&(p->parent[i].textGatherList)); */
-		for (j = 0; j < XML_STACK_MAX_CHILDREN; j++) {
-			p->parent[i].children[j].name = UA_NULL;
-			p->parent[i].children[j].length         = -1;
-			p->parent[i].children[j].elementHandler = UA_NULL;
-			p->parent[i].children[j].type           = UA_INVALIDTYPE;
-			p->parent[i].children[j].obj = UA_NULL;
-		}
-	}
-	/* p->nsid = nsid; */
-	p->parent[0].name = name;
-}
-
-char path_buffer[1024];
-char *XML_Stack_path(XML_Stack *s) {
-	UA_Int32 i;
-	char    *p = &path_buffer[0];
-	for(i = 0;i <= s->depth;i++) {
-		strcpy(p, s->parent[i].name);
-		p += strlen(s->parent[i].name);
-		*p = '/';
-		p++;
-	}
-	*p = 0;
-	return &path_buffer[0];
-}
-
-void XML_Stack_print(XML_Stack *s) {
-	printf("%s", XML_Stack_path(s));
-}
-
-// FIXME: we might want to calculate textAttribIdx from a string and the information given on the stack
-void XML_Stack_handleTextAsElementOf(XML_Stack *p, cstring textAttrib, unsigned int textAttribIdx) {
-	p->parent[p->depth].textAttrib    = textAttrib;
-	p->parent[p->depth].textAttribIdx = textAttribIdx;
-}
-
-void XML_Stack_addChildHandler(XML_Stack *p, cstring name, UA_Int32 length, XML_decoder handler, UA_Int32 type,
-                               void *dst) {
-	unsigned int len = p->parent[p->depth].len;
-	p->parent[p->depth].children[len].name = name;
-	p->parent[p->depth].children[len].length         = length;
-	p->parent[p->depth].children[len].elementHandler = handler;
-	p->parent[p->depth].children[len].type           = type;
-	p->parent[p->depth].children[len].obj = dst;
-	p->parent[p->depth].len++;
-}
-
-UA_Int32 UA_Text_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_Byte **dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_String entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	UA_UInt32 i;
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_alloc((void **)&dst, sizeof(void *));
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		// set attributes
-		for(i = 0;attr[i];i += 2) {
-			if(0 == strncmp("Data", attr[i], strlen("Data"))) {
-				char *tmp;
-				UA_alloc((void **)&tmp, strlen(attr[i+1])+1);
-				strncpy(tmp, attr[i+1], strlen(attr[i+1]));
-				tmp[strlen(attr[i+1])] = 0;
-				*dst = (UA_Byte *)tmp;
-			} else
-				printf("UA_Text_decodeXml - Unknown attribute - name=%s, value=%s\n", attr[i], attr[i+1]);
-		}
-	}
-	return UA_SUCCESS;
-}
-
-// Gets generated in ua_types_generated.h and .c. But currently only as stubs
-/* UA_Int32 UA_ReferenceNode_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_ReferenceNode* dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_ReferenceNode_decodeXML entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); */
-/* 	if (isStart) { */
-/* 		// create if necessary */
-/* 		if (dst == UA_NULL) { */
-/* 			UA_ReferenceNode_new(&dst); */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst; */
-/* 		} */
-/* 		// set handlers */
-/* 		s->parent[s->depth].len = 0; */
-/* 		XML_Stack_addChildHandler(s, "ReferenceType", strlen("ReferenceType"),(XML_decoder) UA_NodeId_decodeXmlFromStack, UA_NODEID, &(dst->referenceTypeId)); */
-/* 		XML_Stack_addChildHandler(s, "IsForward", strlen("IsForward"), (XML_decoder) UA_Boolean_decodeXmlFromStack, UA_BOOLEAN, &(dst->isInverse)); */
-/* 		XML_Stack_addChildHandler(s, "Target", strlen("Target"), (XML_decoder) UA_ExpandedNodeId_decodeXmlFromStack, UA_EXPANDEDNODEID, &(dst->targetId)); */
-/* 		XML_Stack_handleTextAsElementOf(s, "NodeId", 2); */
-
-/* 		// set attributes */
-/* 		UA_Int32 i; */
-/* 		for (i = 0; attr[i]; i += 2) { */
-/* 			if (0 == strncmp("ReferenceType", attr[i], strlen("ReferenceType"))) { */
-/* 				UA_NodeId_copycstring(attr[i + 1], &(dst->referenceTypeId), s->aliases); */
-/* 			} else if (0 == strncmp("IsForward", attr[i], strlen("IsForward"))) { */
-/* 				UA_Boolean_copycstring(attr[i + 1], &(dst->isInverse)); */
-/* 				dst->isInverse = !dst->isInverse; */
-/* 			} else if (0 == strncmp("Target", attr[i], strlen("Target"))) { */
-/* 				UA_ExpandedNodeId_copycstring(attr[i + 1], &(dst->targetId), s->aliases); */
-/* 			} else { */
-/* 				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i])); */
-/* 			} */
-/* 		} */
-/* 	} */
-/* 	return UA_SUCCESS; */
-/* } */
-
-UA_Int32 UA_TypedArray_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_TypedArray* dst, _Bool isStart) {
-	UA_Int32 type = s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].type;
-	/* DBG_VERBOSE(printf("UA_TypedArray_decodeXML - entered with dst=%p,isStart=%d,type={%d,%s},name=%s\n", (void* ) dst, isStart,type,UA_[type].name, names)); */
-	if (isStart) {
-		if (dst == UA_NULL) {
-			UA_TypedArray_new(&dst);
-			UA_TypedArray_setType(dst, type);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = dst;
-		}
-		// need to map from ArrayName to member name
-		// References - Reference
-		// Aliases - Alias
-		// ListOfXX - XX
-		DBG(UA_Int32 length = 0;
-			cstring names  = s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].name;
-			if (0 == strncmp("ListOf",names,strlen("ListOf"))) {
-				names = &names[strlen("ListOf")];
-				length = strlen(names);
-			} else if ( 0 == strncmp("References",names,strlen("References"))){
-				length = strlen(names) - 1;
-			} else if ( 0 == strncmp("Aliases",names,strlen("Aliases"))){
-				length = strlen(names) - 2;
-			}
-			printf("UA_TypedArray_decodeXML - add handler for {%.*s}\n", length, names));
-		// this is problematic as the standard encoding functions in the vtable take a bytestring as the input
-		/* XML_Stack_addChildHandler(s, names, length, (XML_decoder) UA_.types[type].encodings[1].decode, type, UA_NULL); */
-	} else {
-		// sub element is ready, add to array
-		if (dst->size < 0 || dst->size == 0) {
-			dst->size = 1;
-			UA_alloc((void** )&(dst->elements), dst->size * sizeof(void*));
-			DBG(printf("UA_TypedArray_decodeXML - allocate elements:dst=%p, aliases=%p, size=%d\n", (void* )dst, (void* )(dst->elements),dst->size));
-		} else {
-			dst->size++;
-			dst->elements = realloc(dst->elements, dst->size * sizeof(void*));
-			DBG(printf("UA_TypedArray_decodeXML - reallocate elements:dst=%p, aliases=%p, size=%d\n", (void* )dst,(void* )(dst->elements), dst->size));
-		}
-		// index starts with 0, therefore size-1
-		DBG_VERBOSE(printf("UA_TypedArray_decodeXML - assign element[%d], src=%p\n", dst->size - 1, (void* )attr));
-		/* dst->elements[dst->size - 1] = (void*) attr; */
-		DBG_VERBOSE(printf("UA_TypedArray_decodeXML - clear %p\n",(void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
-		s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
-	}
-	return UA_SUCCESS;
-}
-
-// Gets generated in ua_types_generated.h and .c. But currently only as stubs
-/* UA_Int32 UA_DataTypeNode_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_DataTypeNode* dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); */
-/* 	UA_UInt32 i; */
-
-/* 	if (isStart) { */
-/* 		// create a new object if called with UA_NULL */
-/* 		if (dst == UA_NULL) { */
-/* 			UA_DataTypeNode_new(&dst); */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst; */
-/* 		} */
-
-/* 		s->parent[s->depth].len = 0; */
-/* 		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, &(dst->displayName)); */
-/* 		XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"),(XML_decoder) UA_QualifiedName_decodeXmlFromStack, UA_QUALIFIEDNAME, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "IsAbstract", strlen("IsAbstract"),(XML_decoder) UA_Boolean_decodeXmlFromStack, UA_BOOLEAN, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "References", strlen("References"),(XML_decoder) UA_TypedArray_decodeXmlFromStack, UA_REFERENCENODE, UA_NULL); */
-
-/* 		// set missing default attributes */
-/* 		dst->nodeClass = UA_NODECLASS_DATATYPE; */
-
-/* 		// set attributes */
-/* 		for (i = 0; attr[i]; i += 2) { */
-/* 			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) { */
-/* 				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases); */
-/* 			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->browseName.name)); */
-/* 				dst->browseName.namespaceIndex = 0; */
-/* 			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->displayName.text)); */
-/* 				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else if (0 == strncmp("IsAbstract", attr[i], strlen("IsAbstract"))) { */
-/* 				UA_Boolean_copycstring(attr[i + 1], &(dst->isAbstract)); */
-/* 				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->description.text)); */
-/* 				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else { */
-/* 				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i])); */
-/* 			} */
-/* 		} */
-/* 	} else { */
-/* 		switch (s->parent[s->depth - 1].activeChild) { */
-/* 		case 4: // References */
-/* 			if (attr != UA_NULL) { */
-/* 				UA_TypedArray* array = (UA_TypedArray *) attr; */
-/* 				DBG_VERBOSE(printf("finished aliases: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size)); */
-/* 				dst->referencesSize = array->size; */
-/* 				/\* dst->references = (UA_ReferenceNode**) array->elements; *\/ */
-/* 			} */
-/* 		break; */
-/* 		} */
-/* 	} */
-/* 	return UA_SUCCESS; */
-/* } */
-
-// Gets generated in ua_types_generated.h and .c. But currently only as stubs
-/* UA_Int32 UA_ObjectTypeNode_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_ObjectTypeNode* dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); */
-/* 	UA_UInt32 i; */
-
-/* 	if (isStart) { */
-/* 		// create a new object if called with UA_NULL */
-/* 		if (dst == UA_NULL) { */
-/* 			UA_ObjectTypeNode_new(&dst); */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst; */
-/* 		} */
-
-/* 		s->parent[s->depth].len = 0; */
-/* 		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, &(dst->displayName)); */
-/* 		XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"),(XML_decoder) UA_QualifiedName_decodeXmlFromStack, UA_QUALIFIEDNAME, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "IsAbstract", strlen("IsAbstract"),(XML_decoder) UA_Boolean_decodeXmlFromStack, UA_BOOLEAN, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "References", strlen("References"),(XML_decoder) UA_TypedArray_decodeXmlFromStack, UA_REFERENCENODE, UA_NULL); */
-
-/* 		// set missing default attributes */
-/* 		dst->nodeClass = UA_NODECLASS_OBJECTTYPE; */
-
-/* 		// set attributes */
-/* 		for (i = 0; attr[i]; i += 2) { */
-/* 			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) { */
-/* 				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases); */
-/* 			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->browseName.name)); */
-/* 				dst->browseName.namespaceIndex = 0; */
-/* 			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->displayName.text)); */
-/* 				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else if (0 == strncmp("IsAbstract", attr[i], strlen("IsAbstract"))) { */
-/* 				UA_Boolean_copycstring(attr[i + 1], &(dst->isAbstract)); */
-/* 				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->description.text)); */
-/* 				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else { */
-/* 				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i])); */
-/* 			} */
-/* 		} */
-/* 	} else { */
-/* 		switch (s->parent[s->depth - 1].activeChild) { */
-/* 		case 4: // References */
-/* 			if (attr != UA_NULL) { */
-/* 				UA_TypedArray* array = (UA_TypedArray *) attr; */
-/* 				DBG_VERBOSE(printf("finished aliases: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size)); */
-/* 				dst->referencesSize = array->size; */
-/* 				/\* dst->references = (UA_ReferenceNode**) array->elements; *\/ */
-/* 			} */
-/* 		break; */
-/* 		} */
-/* 	} */
-/* 	return UA_SUCCESS; */
-/* } */
-
-// Gets generated in ua_types_generated.h and .c. But currently only as stubs
-/* UA_Int32 UA_VariableTypeNode_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_VariableTypeNode* dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_DataTypeNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); */
-/* 	UA_UInt32 i; */
-
-/* 	if (isStart) { */
-/* 		// create a new object if called with UA_NULL */
-/* 		if (dst == UA_NULL) { */
-/* 			UA_VariableTypeNode_new(&dst); */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst; */
-/* 		} */
-
-/* 		s->parent[s->depth].len = 0; */
-/* 		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, &(dst->displayName)); */
-/* 		XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"),(XML_decoder) UA_QualifiedName_decodeXmlFromStack, UA_QUALIFIEDNAME, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "IsAbstract", strlen("IsAbstract"),(XML_decoder) UA_Boolean_decodeXmlFromStack, UA_BOOLEAN, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "References", strlen("References"),(XML_decoder) UA_TypedArray_decodeXmlFromStack, UA_REFERENCENODE, UA_NULL); */
-
-/* 		// set missing default attributes */
-/* 		dst->nodeClass = UA_NODECLASS_VARIABLETYPE; */
-
-/* 		// set attributes */
-/* 		for (i = 0; attr[i]; i += 2) { */
-/* 			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) { */
-/* 				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases); */
-/* 			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->browseName.name)); */
-/* 				dst->browseName.namespaceIndex = 0; */
-/* 			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->displayName.text)); */
-/* 				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else if (0 == strncmp("IsAbstract", attr[i], strlen("IsAbstract"))) { */
-/* 				UA_Boolean_copycstring(attr[i + 1], &(dst->isAbstract)); */
-/* 				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->description.text)); */
-/* 				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else { */
-/* 				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i])); */
-/* 			} */
-/* 		} */
-/* 	} else { */
-/* 		switch (s->parent[s->depth - 1].activeChild) { */
-/* 		case 4: // References */
-/* 			if (attr != UA_NULL) { */
-/* 				UA_TypedArray* array = (UA_TypedArray *) attr; */
-/* 				DBG_VERBOSE(printf("finished aliases: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size)); */
-/* 				dst->referencesSize = array->size; */
-/* 				/\* dst->references = (UA_ReferenceNode**) array->elements; *\/ */
-/* 			} */
-/* 		break; */
-/* 		} */
-/* 	} */
-/* 	return UA_SUCCESS; */
-/* } */
-
-// Gets generated in ua_types_generated.h and .c. But currently only as stubs
-/* UA_Int32 UA_ObjectNode_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_ObjectNode* dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_ObjectNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); */
-/* 	UA_UInt32 i; */
-
-/* 	if (isStart) { */
-/* 		// create a new object if called with UA_NULL */
-/* 		if (dst == UA_NULL) { */
-/* 			UA_ObjectNode_new(&dst); */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst; */
-/* 		} */
-
-/* 		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, &(dst->displayName)); */
-/* 		XML_Stack_addChildHandler(s, "Description", strlen("Description"), (XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, &(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "BrowseName", strlen("BrowseName"), (XML_decoder) UA_QualifiedName_decodeXmlFromStack, UA_QUALIFIEDNAME, &(dst->browseName)); */
-/* 		XML_Stack_addChildHandler(s, "SymbolicName", strlen("SymbolicName"), (XML_decoder) UA_QualifiedName_decodeXmlFromStack, UA_QUALIFIEDNAME,&(dst->browseName)); */
-/* 		XML_Stack_addChildHandler(s, "References", strlen("References"), (XML_decoder) UA_TypedArray_decodeXmlFromStack, UA_REFERENCENODE, UA_NULL); */
-
-/* 		// set missing default attributes */
-/* 		dst->nodeClass = UA_NODECLASS_OBJECT; */
-
-/* 		// set attributes */
-/* 		for (i = 0; attr[i]; i += 2) { */
-/* 			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) { */
-/* 				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases); */
-/* 			} else if (0 == strncmp("SymbolicName", attr[i], strlen("SymbolicName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->browseName.name)); */
-/* 				dst->browseName.namespaceIndex = 0; */
-/* 			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->browseName.name)); */
-/* 				dst->browseName.namespaceIndex = 0; */
-/* 			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->displayName.text)); */
-/* 				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->description.text)); */
-/* 				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else { */
-/* 				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i])); */
-/* 			} */
-/* 		} */
-/* 	} else { */
-/* 		if (s->parent[s->depth - 1].activeChild == 4 && attr != UA_NULL ) { // References Array */
-/* 			UA_TypedArray* array = (UA_TypedArray*) attr; */
-/* 			DBG(printf("UA_ObjectNode_decodeXML finished references: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size)); */
-/* 			dst->referencesSize = array->size; */
-/* 			/\* dst->references = (UA_ReferenceNode**) array->elements; *\/ */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL; */
-/* 		} */
-/* 	} */
-/* 	return UA_SUCCESS; */
-/* } */
-
-
-// Gets generated in ua_types_generated.h and .c. But currently only as stubs
-/* UA_Int32 UA_Variant_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_Variant* dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_Variant entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); */
-/* 	UA_UInt32 i; */
-
-/* 	if (isStart) { */
-/* 		// create a new object if called with UA_NULL */
-/* 		if (dst == UA_NULL) { */
-/* 			UA_Variant_new(&dst); */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst; */
-/* 		} */
-
-/* 		s->parent[s->depth].len = 0; */
-/* 		XML_Stack_addChildHandler(s, "ListOfExtensionObject", strlen("ListOfExtensionObject"), (XML_decoder) UA_TypedArray_decodeXmlFromStack, UA_EXTENSIONOBJECT, UA_NULL); */
-/* 		XML_Stack_addChildHandler(s, "ListOfLocalizedText", strlen("ListOfLocalizedText"), (XML_decoder) UA_TypedArray_decodeXmlFromStack, UA_LOCALIZEDTEXT, UA_NULL); */
-
-/* 		// set attributes */
-/* 		for (i = 0; attr[i]; i += 2) { */
-/* 			{ */
-/* 				DBG_ERR(XML_Stack_print(s)); */
-/* 				DBG_ERR(printf("%s - unknown attribute\n", attr[i])); */
-/* 			} */
-/* 		} */
-/* 	} else { */
-/* 		if (s->parent[s->depth - 1].activeChild == 0 && attr != UA_NULL ) { // ExtensionObject */
-/* 			UA_TypedArray* array = (UA_TypedArray*) attr; */
-/* 			DBG_VERBOSE(printf("UA_Variant_decodeXML - finished array: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size)); */
-/* 			dst->arrayLength = array->size; */
-/* 			dst->data = array->elements; */
-/* 			dst->vt = &UA_.types[UA_EXTENSIONOBJECT]; */
-/* 			dst->encodingMask = UA_EXTENSIONOBJECT_NS0 & UA_VARIANT_ENCODINGMASKTYPE_ARRAY; */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL; */
-/* 		} else if (s->parent[s->depth - 1].activeChild == 1 && attr != UA_NULL ) { // LocalizedText */
-/* 			UA_TypedArray* array = (UA_TypedArray*) attr; */
-/* 			DBG_VERBOSE(printf("UA_Variant_decodeXML - finished array: references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size)); */
-/* 			dst->arrayLength = array->size; */
-/* 			dst->data = array->elements; */
-/* 			dst->vt = &UA_.types[UA_LOCALIZEDTEXT]; */
-/* 			dst->encodingMask = UA_LOCALIZEDTEXT_NS0 & UA_VARIANT_ENCODINGMASKTYPE_ARRAY; */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL; */
-/* 		} */
-/* 	} */
-/* 	return UA_SUCCESS; */
-/* } */
-
-// Gets generated in ua_types_generated.h and .c. But currently only as stubs
-/* UA_Int32 UA_ExtensionObject_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_ExtensionObject* dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_ExtensionObject entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); */
-/* 	UA_UInt32 i; */
-
-/* 	if (isStart) { */
-/* 		// create a new object if called with UA_NULL */
-/* 		if (dst == UA_NULL) { */
-/* 			UA_ExtensionObject_new(&dst); */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst; */
-/* 		} */
-
-/* 		s->parent[s->depth].len = 0; */
-/* 		XML_Stack_addChildHandler(s, "TypeId", strlen("TypeId"), (XML_decoder) UA_NodeId_decodeXmlFromStack, UA_NODEID, &(dst->typeId)); */
-/* 		// XML_Stack_addChildHandler(s, "Body", strlen("Body"), (XML_decoder) UA_Body_decodeXML, UA_LOCALIZEDTEXT, UA_NULL); */
-
-/* 		// set attributes */
-/* 		for (i = 0; attr[i]; i += 2) { */
-/* 			{ */
-/* 				DBG_ERR(XML_Stack_print(s)); */
-/* 				DBG_ERR(printf("%s - unknown attribute\n", attr[i])); */
-/* 			} */
-/* 		} */
-/* 	} */
-/* 	return UA_SUCCESS; */
-/* } */
-
-_Bool UA_NodeId_isBuiltinType(UA_NodeId* nodeid) {
-	return (nodeid->namespaceIndex == 0 && nodeid->identifier.numeric >= UA_BOOLEAN_NS0 &&
-			nodeid->identifier.numeric <= UA_DIAGNOSTICINFO_NS0
-			);
-}
-
-// Gets generated in ua_types_generated.h and .c. But currently only as stubs
-/* UA_Int32 UA_VariableNode_decodeXmlFromStack(XML_Stack* s, XML_Attr* attr, UA_VariableNode* dst, _Bool isStart) { */
-/* 	DBG_VERBOSE(printf("UA_VariableNode entered with dst=%p,isStart=%d\n", (void* ) dst, isStart)); */
-/* 	UA_UInt32 i; */
-
-/* 	if (isStart) { */
-/* 		// create a new object if called with UA_NULL */
-/* 		if (dst == UA_NULL) { */
-/* 			UA_VariableNode_new(&dst); */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void*) dst; */
-/* 		} */
-
-/* 		s->parent[s->depth].len = 0; */
-/* 		XML_Stack_addChildHandler(s, "DisplayName", strlen("DisplayName"), (XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, */
-/* 				&(dst->displayName)); */
-/* 		XML_Stack_addChildHandler(s, "Description", strlen("Description"),(XML_decoder) UA_LocalizedText_decodeXmlFromStack, UA_LOCALIZEDTEXT, */
-/* 				&(dst->description)); */
-/* 		XML_Stack_addChildHandler(s, "DataType", strlen("DataType"),(XML_decoder) UA_NodeId_decodeXmlFromStack, UA_NODEID, &(dst->dataType)); */
-/* 		XML_Stack_addChildHandler(s, "ValueRank", strlen("ValueRank"),(XML_decoder) UA_Int32_decodeXmlFromStack, UA_INT32, &(dst->valueRank)); */
-/* 		XML_Stack_addChildHandler(s, "Value", strlen("Value"),(XML_decoder) UA_Variant_decodeXmlFromStack, UA_VARIANT, &(dst->value)); */
-/* 		XML_Stack_addChildHandler(s, "References", strlen("References"), (XML_decoder) UA_TypedArray_decodeXmlFromStack, UA_REFERENCENODE, */
-/* 		UA_NULL); */
-
-/* 		// set missing default attributes */
-/* 		dst->nodeClass = UA_NODECLASS_VARIABLE; */
-
-/* 		// set attributes */
-/* 		for (i = 0; attr[i]; i += 2) { */
-/* 			if (0 == strncmp("NodeId", attr[i], strlen("NodeId"))) { */
-/* 				UA_NodeId_copycstring(attr[i + 1], &(dst->nodeId), s->aliases); */
-/* 			} else if (0 == strncmp("DataType", attr[i], strlen("DataType"))) { */
-/* 				UA_NodeId_copycstring(attr[i + 1], &(dst->dataType), s->aliases); */
-/* 				if (UA_NodeId_isBuiltinType(&(dst->dataType))) { */
-/* 					dst->value.encodingMask = dst->dataType.identifier.numeric; */
-/* 					dst->value.vt = &UA_.types[UA_ns0ToVTableIndex(&dst->dataType)]; */
-/* 				} else { */
-/* 					dst->value.encodingMask = UA_EXTENSIONOBJECT_NS0; */
-/* 					dst->value.vt = &UA_.types[UA_EXTENSIONOBJECT]; */
-/* 				} */
-/* 			} else if (0 == strncmp("ValueRank", attr[i], strlen("ValueRank"))) { */
-/* 				dst->valueRank = atoi(attr[i + 1]); */
-/* 			} else if (0 == strncmp("ParentNodeId", attr[i], strlen("ParentNodeId"))) { */
-/* 				// FIXME: this seems to be redundant to the hasProperty-reference */
-/* 			} else if (0 == strncmp("BrowseName", attr[i], strlen("BrowseName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->browseName.name)); */
-/* 				dst->browseName.namespaceIndex = 0; */
-/* 			} else if (0 == strncmp("DisplayName", attr[i], strlen("DisplayName"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->displayName.text)); */
-/* 				dst->displayName.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else if (0 == strncmp("Description", attr[i], strlen("Description"))) { */
-/* 				UA_String_copycstring(attr[i + 1], &(dst->description.text)); */
-/* 				dst->description.encodingMask = UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT; */
-/* 			} else { */
-/* 				DBG_ERR(XML_Stack_print(s)); */
-/* 				DBG_ERR(printf("%s - unknown attribute\n", attr[i])); */
-/* 			} */
-/* 		} */
-/* 	} else { */
-/* 		if (s->parent[s->depth - 1].activeChild == 5 && attr != UA_NULL) { // References */
-/* 			UA_TypedArray* array = (UA_TypedArray*) attr; */
-/* 			DBG(printf("UA_VariableNode_decodeXML - finished references=%p, size=%d\n",(void*)array,(array==UA_NULL)?-1:array->size)); */
-/* 			dst->referencesSize = array->size; */
-/* 			/\* dst->references = (UA_ReferenceNode**) array->elements; *\/ */
-/* 			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL; */
-/* 		} */
-/* 	} */
-/* 	return UA_SUCCESS; */
-/* } */
-
-#ifdef DEBUG
-void print_node(UA_Node const * node) {
-	if (node != UA_NULL) {
-		UA_NodeId_printf("node.nodeId=", &(node->nodeId));
-		printf("\t.browseName='%.*s'\n", node->browseName.name.length, node->browseName.name.data);
-		printf("\t.displayName='%.*s'\n", node->displayName.text.length, node->displayName.text.data);
-		printf("\t.description='%.*s%s'\n", node->description.text.length > 40 ? 40 : node->description.text.length,
-		       node->description.text.data, node->description.text.length > 40 ? "..." : "");
-		printf("\t.nodeClass=%d\n", node->nodeClass);
-		printf("\t.writeMask=%d\n", node->writeMask);
-		printf("\t.userWriteMask=%d\n", node->userWriteMask);
-		printf("\t.references.size=%d\n", node->referencesSize);
-		UA_Int32 i;
-		for(i = 0;i < node->referencesSize;i++) {
-			printf("\t\t.element[%d]", i);
-			UA_ReferenceNode_println("=", &node->references[i]);
-		}
-		switch(node->nodeClass) {
-		case UA_NODECLASS_VARIABLE:
-		{
-			UA_VariableNode const *p = (UA_VariableNode const *)node;
-			printf("\t----- UA_VariableNode ----- \n");
-			UA_NodeId_printf("\t.dataType=", &(p->dataType));
-			printf("\t.valueRank=%d\n", p->valueRank);
-			printf("\t.accessLevel=%d\n", p->accessLevel);
-			printf("\t.userAccessLevel=%d\n", p->userAccessLevel);
-			printf("\t.arrayDimensionsSize=%d\n", p->arrayDimensionsSize);
-			printf("\t.minimumSamplingInterval=%f\n", p->minimumSamplingInterval);
-			printf("\t.historizing=%d\n", p->historizing);
-			printf("\t----- UA_Variant ----- \n");
-			printf("\t.value.type.name=%s\n", p->value.vt->name);
-			printf("\t.value.array.length=%d\n", p->value.arrayLength);
-			UA_Int32 i;
-			UA_Byte *data = (UA_Byte *)p->value.data;
-			for(i = 0;i < p->value.arrayLength || (p->value.arrayLength == -1 && i == 0);++i) {
-				UA_Byte *currentData = data + (i*p->value.vt->memSize);
-				printf("\t.value.array.element[%d]=%p", i, currentData);
-				switch(p->value.vt->typeId.identifier.numeric) {
-				case UA_LOCALIZEDTEXT_NS0:
-				{
-					if(p->value.data != UA_NULL) {
-						UA_LocalizedText *ltp = (UA_LocalizedText *)currentData;
-						printf(",locale={%d,{%.*s}},text={%d,{%.*s}}", ltp->locale.length,
-							   ltp->locale.length, ltp->locale.data, ltp->text.length,
-							   ltp->text.length, ltp->text.data);
-					}
-				}
-				break;
-
-				case UA_EXTENSIONOBJECT_NS0:
-				{
-					if(p->value.data != UA_NULL) {
-						UA_ExtensionObject *eo = (UA_ExtensionObject *)currentData;
-						if(eo == UA_NULL)
-							printf(",(null)");
-						else
-							printf(",enc=%d,typeId={i=%d}", eo->encoding, eo->typeId.identifier.numeric);
-					}
-				}
-				break;
-
-				default:
-					break;
-				}
-				printf("\n");
-			}
-		}
-		break;
-
-		// case UA_NODECLASS_DATATYPE:
-		default:
-			break;
-		}
-	}
-}
-#endif
-
-UA_Int32 UA_NodeSetAlias_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_NodeSetAlias *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_NodeSetAlias entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	if(isStart) {
-		// create if necessary
-		if(dst == UA_NULL) {
-			UA_NodeSetAlias_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		// set handlers
-		s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "Alias", strlen("Alias"), (XML_decoder)UA_String_decodeXmlFromStack, UA_STRING,
-		                          &(dst->alias));
-		XML_Stack_addChildHandler(s, "Value", strlen("Value"), (XML_decoder)UA_String_decodeXmlFromStack, UA_STRING,
-		                          &(dst->value));
-		XML_Stack_handleTextAsElementOf(s, "Data", 1);
-
-		// set attributes
-		UA_Int32 i;
-		for(i = 0;attr[i];i += 2) {
-			if(0 == strncmp("Alias", attr[i], strlen("Alias")))
-				UA_String_copycstring(attr[i + 1], &(dst->alias));
-			else if(0 == strncmp("Value", attr[i], strlen("Value")))
-				UA_String_copycstring(attr[i + 1], &(dst->value));
-			else {
-				DBG_ERR(XML_Stack_print(s)); DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
-			}
-		}
-	}
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_NodeSetAliases_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_NodeSetAliases *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_NodeSetALiases entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_NodeSetAliases_new(&dst);
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "Alias", strlen(
-		                              "Alias"), (XML_decoder)UA_NodeSetAlias_decodeXmlFromStack, UA_INVALIDTYPE,
-		                          UA_NULL);
-	} else {
-		// sub element is ready, add to array
-		if(dst->size < 0 || dst->size == 0) {
-			dst->size = 1;
-			UA_alloc((void ** )&(dst->aliases), dst->size * sizeof(UA_NodeSetAlias *));
-			DBG_VERBOSE(
-			    printf("allocate aliases:dst=%p, aliases=%p, size=%d\n", (void * )dst, (void * )(dst->aliases),
-			           dst->size));
-		} else {
-			dst->size++;
-			dst->aliases = realloc(dst->aliases, dst->size * sizeof(UA_NodeSetAlias *));
-			DBG_VERBOSE(
-			    printf("reallocate aliases:dst=%p, aliases=%p, size=%d\n", (void * )dst, (void * )(dst->aliases),
-			           dst->size));
-		}
-		// index starts with 0, therefore size-1
-		DBG_VERBOSE(printf("assign alias:dst=%p, src=%p\n", (void * )dst->aliases[dst->size - 1], (void * )attr));
-		dst->aliases[dst->size - 1] = (UA_NodeSetAlias *)attr;
-		DBG_VERBOSE(printf("UA_NodeSetAliases clears %p\n",
-		                   (void * )(s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
-		s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
-	}
-	return UA_SUCCESS;
-}
-
-UA_Int32 UA_NodeSet_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_NodeSet *dst, _Bool isStart) {
-	DBG_VERBOSE(printf("UA_NodeSet entered with dst=%p,isStart=%d\n", (void * )dst, isStart));
-	if(isStart) {
-		if(dst == UA_NULL) {
-			UA_NodeSet_new(&dst, 99); // we don't really need the namespaceid for this..'
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = (void *)dst;
-		}
-		s->parent[s->depth].len = 0;
-		XML_Stack_addChildHandler(s, "Aliases", strlen(
-		                              "Aliases"), (XML_decoder)UA_NodeSetAliases_decodeXmlFromStack, UA_INVALIDTYPE,
-		                          &(dst->aliases));
-		XML_Stack_addChildHandler(s, "UADataType", strlen(
-		                              "UADataType"), (XML_decoder)UA_DataTypeNode_decodeXmlFromStack, UA_DATATYPENODE,
-		                          UA_NULL);
-		XML_Stack_addChildHandler(s, "UAVariableType", strlen(
-		                              "UAVariableType"), (XML_decoder)UA_VariableTypeNode_decodeXmlFromStack,
-		                          UA_VARIABLETYPENODE, UA_NULL);
-		XML_Stack_addChildHandler(s, "UAVariable", strlen(
-		                              "UAVariable"), (XML_decoder)UA_VariableNode_decodeXmlFromStack, UA_VARIABLENODE,
-		                          UA_NULL);
-		XML_Stack_addChildHandler(s, "UAObjectType", strlen(
-		                              "UAObjectType"), (XML_decoder)UA_ObjectTypeNode_decodeXmlFromStack,
-		                          UA_OBJECTTYPENODE, UA_NULL);
-		XML_Stack_addChildHandler(s, "UAObject", strlen(
-		                              "UAObject"), (XML_decoder)UA_ObjectNode_decodeXmlFromStack, UA_OBJECTNODE,
-		                          UA_NULL);
-	} else {
-		if(s->parent[s->depth - 1].activeChild == 0 && attr != UA_NULL) {
-			UA_NodeSetAliases *aliases = (UA_NodeSetAliases *)attr;
-			DBG(printf("UA_NodeSet_decodeXml - finished aliases: aliases=%p, size=%d\n", (void *)aliases,
-			           (aliases == UA_NULL) ? -1 : aliases->size));
-			s->aliases = aliases;
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
-		} else {
-			UA_Node* node = (UA_Node*) attr;
-			DBG(printf("UA_NodeSet_decodeXML - finished node: node=%p\n", (void* )node));
-			Namespace_insert(dst->ns, &node, 0);
-			DBG(printf("UA_NodeSet_decodeXml - Inserting "));
-			s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
-		}
-	}
-	return UA_SUCCESS;
-}
-
-/** lookup if element is a known child of parent, if yes go for it otherwise ignore */
-void XML_Stack_startElement(void *data, const char *el, const char **attr) {
-	XML_Stack  *s = (XML_Stack *)data;
-	int         i;
-
-// scan expected children
-	XML_Parent *cp = &s->parent[s->depth];
-	for(i = 0;i < cp->len;i++) {
-		if(0 == strncmp(cp->children[i].name, el, cp->children[i].length)) {
-			DBG_VERBOSE(XML_Stack_print(s));
-			DBG_VERBOSE(printf("%s - processing\n", el));
-
-			cp->activeChild = i;
-
-			s->depth++;
-			s->parent[s->depth].name = el;
-			s->parent[s->depth].len  = 0;
-			s->parent[s->depth].textAttribIdx = -1;
-			s->parent[s->depth].activeChild   = -1;
-
-			// finally call the elementHandler and return
-			cp->children[i].elementHandler(data, attr, cp->children[i].obj, TRUE);
-			return;
-		}
-	}
-// if we come here we rejected the processing of el
-	DBG_VERBOSE(XML_Stack_print(s));
-	DBG_VERBOSE(printf("%s - rejected\n", el));
-	s->depth++;
-	s->parent[s->depth].name = el;
-// this should be sufficient to reject the children as well
-	s->parent[s->depth].len  = 0;
-}
-
-UA_Int32 XML_isSpace(cstring s, int len) {
-	int i;
-	for(i = 0;i < len;i++) {
-		if(!isspace(s[i]))
-			return UA_FALSE;
-	}
-	return UA_TRUE;
-}
-
-/* gather text */
-void XML_Stack_handleText(void * data, const char *txt, int len) {
-	/* XML_Stack* s = (XML_Stack*) data; */
-
-	if (len > 0 && !XML_isSpace(txt, len)) {
-		/* XML_Parent* cp = &(s->parent[s->depth]); // determine current element */
-		UA_ByteString src = { len+1, (UA_Byte*) txt };
-		UA_ByteString *dst;
-		UA_ByteString_new(&dst);	// alloc dst
-		UA_ByteString_copy(&src,dst); // alloc dst->data and copy txt
-		dst->data[len] = 0; // add terminating zero to handle single line efficiently
-		/* UA_list_addPayloadToBack(&(cp->textGatherList), (void*) dst); */
-		/* if (cp->totalGatherLength == -1) { */
-		/* 	cp->totalGatherLength = len; */
-		/* } else { */
-		/* 	cp->totalGatherLength += len; */
-		/* } */
-	}
-}
-
-char* theGatherBuffer;
-void textGatherListTotalLength(void* payload) {
-	UA_ByteString* b = (UA_ByteString*) payload;
-	#ifdef DEBUG
-	UA_ByteString_printf("\t",b);
-	#endif
-	UA_memcpy(theGatherBuffer,b->data,b->length-1); // remove trailing zero
-	theGatherBuffer += (b->length-1);
-}
-/** if we are an activeChild of a parent we call the child-handler */
-void XML_Stack_endElement(void *data, const char *el) {
-	/* XML_Stack *s = (XML_Stack *)data; */
-
-	/* XML_Parent* ce = &(s->parent[s->depth]); */
-	/* if (ce->textAttribIdx >= 0 && ce->totalGatherLength > 0 ) { */
-	/* 	ce->activeChild = ce->textAttribIdx; */
-	/* 	char* buf; */
-	/* 	if (UA_list_getFirst(&(ce->textGatherList)) == UA_list_getLast(&(ce->textGatherList)) ) { */
-	/* 		buf = (char*) ((UA_ByteString*) UA_list_getFirst(&(ce->textGatherList))->payload)->data; */
-	/* 	} else { */
-	/* 		printf("XML_Stack_endElement - more than one text snippet with total length=%d:\n",ce->totalGatherLength); */
-	/* 		UA_alloc((void**)&theGatherBuffer,ce->totalGatherLength+1); */
-	/* 		buf = theGatherBuffer; */
-	/* 		UA_list_iteratePayload(&(ce->textGatherList), textGatherListTotalLength); */
-	/* 		buf[ce->totalGatherLength] = 0; */
-	/* 		printf("XML_Stack_endElement - gatherBuffer %s:\n",buf); */
-	/* 	} */
-	/* 	XML_Attr attr[3] = { ce->textAttrib, buf, UA_NULL }; */
-	/* 	DBG(printf("handleText @ %s calls start elementHandler %s with dst=%p, buf={%s}\n", XML_Stack_path(s),ce->children[ce->activeChild].name, ce->children[ce->activeChild].obj, buf)); */
-	/* 	ce->children[ce->activeChild].elementHandler(s, attr, ce->children[ce->activeChild].obj, TRUE); */
-	/* 	if (s->parent[s->depth-1].activeChild > 0) { */
-	/* 		XML_child* c = &(s->parent[s->depth-1].children[s->parent[s->depth-1].activeChild]); */
-	/* 		c->elementHandler(s, UA_NULL, c->obj, FALSE); */
-	/* 	} */
-	/* 	if (UA_list_getFirst(&(ce->textGatherList)) != UA_list_getLast(&(ce->textGatherList)) ) { */
-	/* 		UA_free(buf); */
-	/* 	} */
-	/* 	UA_list_destroy(&(ce->textGatherList),(UA_list_PayloadVisitor) UA_ByteString_delete); */
-	/* 	UA_list_init(&(ce->textGatherList)); // don't know if destroy leaves the list in usable state... */
-	/* 	ce->totalGatherLength = -1; */
-	/* } */
-
-	/* // the parent of the parent (pop) of the element knows the elementHandler, therefore depth-2! */
-	/* if (s->depth > 1) { */
-	/* 	// inform parents elementHandler that everything is done */
-	/* 	XML_Parent *cp  = &(s->parent[s->depth - 1]); */
-	/* 	XML_Parent *cpp = &(s->parent[s->depth - 2]); */
-	/* 	if(cpp->activeChild >= 0 && cp->activeChild >= 0) { */
-	/* 		DBG_VERBOSE(XML_Stack_print(s)); */
-	/* 		DBG_VERBOSE( */
-	/* 		    printf(" - inform pop %s, arg=%p\n", cpp->children[cpp->activeChild].name, */
-	/* 		           (void * )cp->children[cp->activeChild].obj)); */
-	/* 		cpp->children[cpp->activeChild].elementHandler(s, (XML_Attr *)cp->children[cp->activeChild].obj, */
-	/* 		                                               cpp->children[cpp->activeChild].obj, FALSE); */
-	/* 	} */
-	/* 	// reset */
-	/* 	cp->activeChild = -1; */
-	/* } */
-	/* s->depth--; */
-}

+ 0 - 134
src/ongoing/ua_xml.h

@@ -1,134 +0,0 @@
-#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 "ua_types.h"
-
-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);
-
-/** @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_PROTOTYPES(UA_NodeSetAlias)
-
-/** @brief UA_NodeSetAliases - a list of aliases */
-typedef struct UA_NodeSetAliases {
-	UA_Int32 size;
-	UA_NodeSetAlias **aliases;
-} UA_NodeSetAliases;
-//UA_TYPE_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_NodeSetAliases *aliases;  // shall point to the aliases of the NodeSet after reading
-} XML_Stack;
-
-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);
-
-/** @brief an object to hold a typed array */
-typedef struct UA_TypedArray {
-	UA_Int32         size;
-	UA_VTable_Entry *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, UA_Boolean isStart);
-
-UA_Int32 UA_NodeSetAlias_init(UA_NodeSetAlias* p);
-UA_Int32 UA_NodeSetAlias_new(UA_NodeSetAlias** p);
-
-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_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);
-
-UA_Int32 UA_Text_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_Byte **dst, _Bool isStart);
-UA_Int32 UA_NodeId_copycstring(cstring src, UA_NodeId *dst, UA_NodeSetAliases *aliases);
-UA_Int32 UA_TypedArray_decodeXmlFromStack(XML_Stack *s, XML_Attr *attr, UA_TypedArray *dst, _Bool isStart);
-
-#endif // __UA_XML_H__

+ 0 - 210
src/ongoing/xml2ns0.c

@@ -1,210 +0,0 @@
-#include <fcntl.h> // open, O_RDONLY
-#include "ua_types.h"
-//#include "ua_types_generated.h"
-#include "ua_namespace.h"
-#include "ua_xml.h"
-#include "ua_namespace_xml.h"
-#include "ua_types_encoding_xml.h"
-#include "util/ua_util.h"
-
-// FIXME: most of the following code should be generated as a template from the ns0-defining xml-files
-/** @brief sam (abbr. for server_application_memory) is a flattened memory structure of the UAVariables in ns0 */
-struct sam {
-	UA_ServerStatusDataType serverStatus;
-} sam;
-
-char* productName = "xml2ns0";
-char* productUri = "http://open62541.org/xml2ns0/";
-char* manufacturerName = "open62541";
-char* softwareVersion = "0.01";
-char* buildNumber = "999-" __DATE__ "-001" ;
-
-#define SAM_ASSIGN_CSTRING(src,dst) do { \
-	dst.length = strlen(src)-1; \
-	dst.data = (UA_Byte*) src; \
-} while(0)
-
-void sam_attach(Namespace *ns,UA_UInt32 ns0id,UA_Int32 type, void* p) {
-	UA_NodeId nodeid;
-	nodeid.namespace = 0; // we cannot access ns->namespaceIndex;
-	nodeid.identifier.numeric = ns0id;
-	nodeid.encodingByte = UA_NODEIDTYPE_FOURBYTE;
-	const UA_Node* result;
-	UA_Int32 retval = Namespace_get(ns,&nodeid,&result);
-	if (retval == UA_SUCCESS) {
-		if (result->nodeId.identifier.numeric == ns0id) {
-			if (result->nodeClass == UA_NODECLASS_VARIABLE) {
-				UA_VariableNode* variable = (UA_VariableNode*) result;
-				if (variable->dataType.identifier.numeric == UA_.types[type].typeId.identifier.numeric) {
-					variable->value.arrayLength = 1;
-					variable->value.data = p;
-				} else {
-					UA_alloc((void**)&variable->value.data, sizeof(UA_ExtensionObject));
-					UA_ExtensionObject* eo = (UA_ExtensionObject*) variable->value.data;
-					eo->typeId = variable->dataType;
-					eo->encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
-					// FIXME: This code is valid for ns0 and numeric identifiers only
-					eo->body.length = UA_.types[UA_ns0ToVTableIndex(&variable->dataType)].memSize;
-					eo->body.data = p;
-				}
-			}
-		}
-		Namespace_releaseManagedNode(result);
-	}
-}
-	/* 	} else { */
-	/* 		perror("Namespace_getWritable returned wrong node class"); */
-	/* 	} */
-	/* } else { */
-	/* 	printf("retrieving node={i=%d} returned node={i=%d}\n", ns0id, result->nodeId.identifier.numeric); */
-	/* } */
-	/*        Namespace_Entry_Lock_release(lock); */
-	/* 	} else { */
-	/* 	printf("retrieving node={i=%d} returned error code %d\n",ns0id,retval); */
-	/* } */
-
-void sam_init(Namespace* ns) {
-	// Initialize the strings
-	SAM_ASSIGN_CSTRING(productName,sam.serverStatus.buildInfo.productName);
-	SAM_ASSIGN_CSTRING(productUri,sam.serverStatus.buildInfo.productUri);
-	SAM_ASSIGN_CSTRING(manufacturerName,sam.serverStatus.buildInfo.manufacturerName);
-	SAM_ASSIGN_CSTRING(softwareVersion,sam.serverStatus.buildInfo.softwareVersion);
-	SAM_ASSIGN_CSTRING(buildNumber,sam.serverStatus.buildInfo.buildNumber);
-
-	// Attach server application memory to ns0
-	sam_attach(ns,2256,UA_SERVERSTATUSDATATYPE,&sam.serverStatus); // this is the head of server status!
-	sam.serverStatus.startTime = sam.serverStatus.currentTime = UA_DateTime_now();
-	sam_attach(ns,2257,UA_DATETIME, &sam.serverStatus.startTime);
-	sam_attach(ns,2258,UA_DATETIME, &sam.serverStatus.currentTime);
-	sam_attach(ns,2259,UA_SERVERSTATE, &sam.serverStatus.state);
-	sam_attach(ns,2260,UA_BUILDINFO, &sam.serverStatus.buildInfo); // start of build Info
-	sam_attach(ns,2261,UA_STRING, &sam.serverStatus.buildInfo.productName);
-	sam_attach(ns,2262,UA_STRING, &sam.serverStatus.buildInfo.productUri);
-	sam_attach(ns,2263,UA_STRING, &sam.serverStatus.buildInfo.manufacturerName);
-	sam_attach(ns,2264,UA_STRING, &sam.serverStatus.buildInfo.softwareVersion);
-	sam_attach(ns,2265,UA_STRING, &sam.serverStatus.buildInfo.buildNumber);
-	sam_attach(ns,2266,UA_DATETIME, &sam.serverStatus.buildInfo.buildDate);
-	sam_attach(ns,2992,UA_UINT32, &sam.serverStatus.secondsTillShutdown);
-	sam_attach(ns,2993,UA_LOCALIZEDTEXT,&sam.serverStatus.shutdownReason);
-}
-
-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_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++;
-		}
-	}
-	Namespace_releaseManagedNode(node);
-	*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_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);
-				Namespace_releaseManagedNode(node);
-				return retval;
-			}
-		}
-	}
-
-	Namespace_releaseManagedNode(node);
-	return UA_ERR_INVALID_VALUE;
-}
-
-
-UA_Int32 UAX_NodeId_encodeBinaryByMetaData(Namespace const * ns, UA_NodeId const * id, UA_ByteString *dst, UA_UInt32* offset) {
-	UA_Int32 i, retval = UA_SUCCESS;
-	if (UA_NodeId_isBasicType(id)) {
-		UA_Node const * result;
-		if ((retval = Namespace_get(ns,id,&result)) == UA_SUCCESS) {
-			UA_Variant_encodeBinary(&((UA_VariableNode *) result)->value,dst,offset);
-			Namespace_releaseManagedNode(result);
-		}
-	} 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, dst, offset);
-			}
-		}
-	}
-	return retval;
-}
-
-UA_Int32 UAX_NodeId_encodeBinary(Namespace const * ns, UA_NodeId const * id, UA_ByteString *dst, UA_UInt32* offset) {
-	UA_Int32 retval = UA_SUCCESS;
-	UA_Node const * node;
-	if ((retval = Namespace_get(ns,id,&node)) == UA_SUCCESS) {
-		if (node->nodeClass == UA_NODECLASS_VARIABLE) {
-			retval = UA_Variant_encodeBinary(&((UA_VariableNode*) node)->value,dst,offset);
-		}
-		Namespace_releaseManagedNode(node);
-	}
-	return retval;
-}
-
-int main() {
-	Namespace* ns;
-	UA_Int32 retval;
-
-	retval = Namespace_loadFromFile(&ns, 0, "ROOT", UA_NULL);
-
-	sam_init(ns);
-	// Namespace_iterate(ns, print_node);
-
-	// encoding buffer
-	char buf[1024];
-	UA_ByteString buffer = { 1024, (UA_Byte*) buf };
-	UA_UInt32 pos = 0;
-
-	UA_NodeId nodeid;
-	nodeid.encodingByte = UA_NODEIDTYPE_FOURBYTE;
-	nodeid.namespace = 0;
-	nodeid.identifier.numeric = 2256; // ServerStatus
-
-	UA_Int32 i=0;
-	retval=UA_SUCCESS;
-	UA_DateTime tStart = UA_DateTime_now();
-	// encoding takes roundabout 10 µs on my virtual machine with -O0, so 1E5 takes a second
-	for (i=0;i<1E5 && retval == UA_SUCCESS;i++) {
-		pos = 0;
-		sam.serverStatus.currentTime = UA_DateTime_now();
-		retval |= UAX_NodeId_encodeBinary(ns,&nodeid,&buffer,&pos);
-	}
-	UA_DateTime tEnd = UA_DateTime_now();
-	// tStart, tEnd count in 100 ns steps, so 10 steps = 1 µs
-	UA_Double tDelta = ( tEnd - tStart ) / ( 10.0 * i );
-
-	printf("encode server node %d times, retval=%d: time/enc=%f us, enc/s=%f\n",i, retval, tDelta, 1.0E6 / tDelta);
-	DBG(buffer.length=pos);
-	DBG(UA_ByteString_printx(", result=", &buffer));
-
-	// Design alternative two : use meta data
-	// pos = 0;
-	// buffer.length = 1024;
-	// UAX_NodeId_encodeBinary(n.ns,&nodeid,&pos,&buffer);
-	// buffer.length = pos;
-	// UA_ByteString_printx("namespace based encoder result=", &buffer);
-
-	return 0;
-}

+ 14 - 10
src/server/ua_nodes.c

@@ -197,7 +197,8 @@ void UA_VariableNode_init(UA_VariableNode *p) {
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_VARIABLE;
     p->valueSource = UA_VALUESOURCE_VARIANT;
-    UA_Variant_init(&p->value.variant);
+    UA_Variant_init(&p->value.variant.value);
+    p->value.variant.callback = (UA_ValueCallback){UA_NULL,UA_NULL,UA_NULL};
     p->valueRank = -2; // scalar or array of any dimension
     p->accessLevel = 0;
     p->userAccessLevel = 0;
@@ -215,7 +216,7 @@ UA_VariableNode * UA_VariableNode_new(void) {
 void UA_VariableNode_deleteMembers(UA_VariableNode *p) {
     UA_Node_deleteMembers((UA_Node*)p);
     if(p->valueSource == UA_VALUESOURCE_VARIANT)
-        UA_Variant_deleteMembers(&p->value.variant);
+        UA_Variant_deleteMembers(&p->value.variant.value);
 }
 
 void UA_VariableNode_delete(UA_VariableNode *p) {
@@ -228,9 +229,10 @@ UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
     dst->valueRank = src->valueRank;
     dst->valueSource = src->valueSource;
-    if(src->valueSource == UA_VALUESOURCE_VARIANT)
-        retval = UA_Variant_copy(&src->value.variant, &dst->value.variant);
-    else
+    if(src->valueSource == UA_VALUESOURCE_VARIANT){
+        retval = UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
+        dst->value.variant.callback = src->value.variant.callback;
+    }else
         dst->value.dataSource = src->value.dataSource;
     if(retval) {
         UA_VariableNode_deleteMembers(dst);
@@ -248,7 +250,8 @@ void UA_VariableTypeNode_init(UA_VariableTypeNode *p) {
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_VARIABLETYPE;
     p->valueSource = UA_VALUESOURCE_VARIANT;
-    UA_Variant_init(&p->value.variant);
+    UA_Variant_init(&p->value.variant.value);
+    p->value.variant.callback = (UA_ValueCallback){UA_NULL, UA_NULL, UA_NULL};
     p->valueRank = -2; // scalar or array of any dimension
     p->isAbstract = UA_FALSE;
 }
@@ -263,7 +266,7 @@ UA_VariableTypeNode * UA_VariableTypeNode_new(void) {
 void UA_VariableTypeNode_deleteMembers(UA_VariableTypeNode *p) {
     UA_Node_deleteMembers((UA_Node*)p);
     if(p->valueSource == UA_VALUESOURCE_VARIANT)
-        UA_Variant_deleteMembers(&p->value.variant);
+        UA_Variant_deleteMembers(&p->value.variant.value);
 }
 
 void UA_VariableTypeNode_delete(UA_VariableTypeNode *p) {
@@ -276,9 +279,10 @@ UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_Variab
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
     dst->valueRank = src->valueRank;
     dst->valueSource = src->valueSource;
-    if(src->valueSource == UA_VALUESOURCE_VARIANT)
-        UA_Variant_copy(&src->value.variant, &dst->value.variant);
-    else
+    if(src->valueSource == UA_VALUESOURCE_VARIANT){
+        UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
+        dst->value.variant.callback = src->value.variant.callback;
+    }else
         dst->value.dataSource = src->value.dataSource;
     if(retval) {
         UA_VariableTypeNode_deleteMembers(dst);

+ 8 - 2
src/server/ua_nodes.h

@@ -68,7 +68,10 @@ typedef struct {
                              n = -3:  the value can be a scalar or a one dimensional array. */
     UA_ValueSource valueSource;
     union {
-        UA_Variant variant;
+        struct {
+        UA_Variant value;
+        UA_ValueCallback callback;
+        } variant;
         UA_DataSource dataSource;
     } value;
     /* <--- similar to variabletypenodes up to there--->*/
@@ -90,7 +93,10 @@ typedef struct {
     UA_Int32 valueRank;
     UA_ValueSource valueSource;
     union {
-        UA_Variant variant;
+        struct {
+            UA_Variant value;
+            UA_ValueCallback callback;
+        } variant;
         UA_DataSource dataSource;
     } value;
     /* <--- similar to variablenodes up to there--->*/

+ 68 - 78
src/server/ua_server.c

@@ -107,9 +107,9 @@ UA_Logger UA_Server_getLogger(UA_Server *server) {
     return server->logger;
 }
 
-void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer) {
-    UA_ServerNetworkLayer *newlayers = UA_realloc(server->networkLayers,
-                                                  sizeof(UA_ServerNetworkLayer)*(server->networkLayersSize+1));
+void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *networkLayer) {
+    UA_ServerNetworkLayer **newlayers =
+        UA_realloc(server->networkLayers, sizeof(void*)*(server->networkLayersSize+1));
     if(!newlayers) {
         UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Networklayer added");
         return;
@@ -127,12 +127,12 @@ void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkL
         return;
     }
     server->description.discoveryUrls = newUrls;
-    UA_String_copy(&networkLayer.discoveryUrl,
+    UA_String_copy(&networkLayer->discoveryUrl,
                    &server->description.discoveryUrls[server->description.discoveryUrlsSize]);
     server->description.discoveryUrlsSize++;
     for(UA_Int32 i = 0; i < server->endpointDescriptionsSize; i++)
         if(!server->endpointDescriptions[i].endpointUrl.data)
-            UA_String_copy(&networkLayer.discoveryUrl, &server->endpointDescriptions[i].endpointUrl);
+            UA_String_copy(&networkLayer->discoveryUrl, &server->endpointDescriptions[i].endpointUrl);
 }
 
 void UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate) {
@@ -169,8 +169,9 @@ void UA_Server_delete(UA_Server *server) {
 
     // Delete the network layers
     for(size_t i = 0; i < server->networkLayersSize; i++) {
-        UA_String_deleteMembers(&server->networkLayers[i].discoveryUrl);
-        server->networkLayers[i].deleteMembers(&server->networkLayers[i]);
+        UA_String_deleteMembers(&server->networkLayers[i]->discoveryUrl);
+        server->networkLayers[i]->deleteMembers(server->networkLayers[i]);
+        UA_free(server->networkLayers[i]);
     }
     UA_free(server->networkLayers);
 
@@ -305,7 +306,7 @@ createVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid,
     copyNames((UA_Node*)variabletype, name);
     variabletype->nodeId.identifier.numeric = variabletypeid;
     variabletype->isAbstract = abstract;
-    variabletype->value.variant.type = &UA_TYPES[UA_TYPES_VARIANT];
+    variabletype->value.variant.value.type = &UA_TYPES[UA_TYPES_VARIANT];
     return variabletype;
 }
 
@@ -840,22 +841,20 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
                                                        .write = UA_NULL};
    namespaceArray->valueRank = 1;
    namespaceArray->minimumSamplingInterval = 1.0;
-   UA_Server_addNode(server, (UA_Node*)namespaceArray, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
-                     nodeIdHasProperty);
+   UA_Server_addNode(server, (UA_Node*)namespaceArray, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), nodeIdHasTypeDefinition,
                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
    UA_VariableNode *serverArray = UA_VariableNode_new();
    copyNames((UA_Node*)serverArray, "ServerArray");
    serverArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERARRAY;
-   serverArray->value.variant.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
-   serverArray->value.variant.arrayLength = 1;
-   serverArray->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
-   *(UA_String *)serverArray->value.variant.data = UA_STRING_ALLOC(server->config.Application_applicationURI);
+   serverArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
+   serverArray->value.variant.value.arrayLength = 1;
+   serverArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+   *(UA_String *)serverArray->value.variant.value.data = UA_STRING_ALLOC(server->config.Application_applicationURI);
    serverArray->valueRank = 1;
    serverArray->minimumSamplingInterval = 1.0;
-   UA_Server_addNode(server, (UA_Node*)serverArray, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
-                     nodeIdHasProperty);
+   UA_Server_addNode(server, (UA_Node*)serverArray, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY),
                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
@@ -864,17 +863,16 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
    UA_Server_addNode(server, (UA_Node*)servercapablities, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
                      nodeIdHasComponent);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
-                          nodeIdHasTypeDefinition,
+   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasTypeDefinition,
                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE));
 
    UA_VariableNode *localeIdArray = UA_VariableNode_new();
    copyNames((UA_Node*)localeIdArray, "LocaleIdArray");
    localeIdArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY;
-   localeIdArray->value.variant.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
-   localeIdArray->value.variant.arrayLength = 1;
-   localeIdArray->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
-   *(UA_String *)localeIdArray->value.variant.data = UA_STRING_ALLOC("en");
+   localeIdArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
+   localeIdArray->value.variant.value.arrayLength = 1;
+   localeIdArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+   *(UA_String *)localeIdArray->value.variant.value.data = UA_STRING_ALLOC("en");
    localeIdArray->valueRank = 1;
    localeIdArray->minimumSamplingInterval = 1.0;
    UA_Server_addNode(server, (UA_Node*)localeIdArray,
@@ -886,9 +884,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     copyNames((UA_Node*)maxBrowseContinuationPoints, "MaxBrowseContinuationPoints");
     maxBrowseContinuationPoints->nodeId.identifier.numeric =
         UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS;
-    maxBrowseContinuationPoints->value.variant.data = UA_UInt16_new();
-    *((UA_UInt16*)maxBrowseContinuationPoints->value.variant.data) = MAXCONTINUATIONPOINTS;
-    maxBrowseContinuationPoints->value.variant.type = &UA_TYPES[UA_TYPES_UINT16];
+    maxBrowseContinuationPoints->value.variant.value.data = UA_UInt16_new();
+    *((UA_UInt16*)maxBrowseContinuationPoints->value.variant.value.data) = MAXCONTINUATIONPOINTS;
+    maxBrowseContinuationPoints->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT16];
     UA_Server_addNode(server, (UA_Node*)maxBrowseContinuationPoints,
                       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
     UA_Server_addReference(server,
@@ -915,11 +913,11 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     UA_VariableNode *serverProfileArray = UA_VariableNode_new();
     copyNames((UA_Node*)serverProfileArray, "ServerProfileArray");
     serverProfileArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY;
-    serverProfileArray->value.variant.arrayLength = profileArraySize;
-    serverProfileArray->value.variant.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], profileArraySize);
-    serverProfileArray->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+    serverProfileArray->value.variant.value.arrayLength = profileArraySize;
+    serverProfileArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], profileArraySize);
+    serverProfileArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     for(UA_UInt16 i=0;i<profileArraySize;i++){
-        ((UA_String *)serverProfileArray->value.variant.data)[i] = profileArray[i];
+        ((UA_String *)serverProfileArray->value.variant.value.data)[i] = profileArray[i];
     }
     serverProfileArray->valueRank = 1;
     serverProfileArray->minimumSamplingInterval = 1.0;
@@ -940,8 +938,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     UA_VariableNode *enabledFlag = UA_VariableNode_new();
      copyNames((UA_Node*)enabledFlag, "EnabledFlag");
      enabledFlag->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG;
-     enabledFlag->value.variant.data = UA_Boolean_new(); //initialized as false
-     enabledFlag->value.variant.type = &UA_TYPES[UA_TYPES_BOOLEAN];
+     enabledFlag->value.variant.value.data = UA_Boolean_new(); //initialized as false
+     enabledFlag->value.variant.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
      enabledFlag->valueRank = 1;
      enabledFlag->minimumSamplingInterval = 1.0;
      UA_Server_addNode(server, (UA_Node*)enabledFlag,
@@ -962,9 +960,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
      UA_VariableNode *starttime = UA_VariableNode_new();
       copyNames((UA_Node*)starttime, "StartTime");
       starttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME);
-      starttime->value.variant.storageType = UA_VARIANT_DATA_NODELETE;
-      starttime->value.variant.data = &server->startTime;
-      starttime->value.variant.type = &UA_TYPES[UA_TYPES_DATETIME];
+      starttime->value.variant.value.storageType = UA_VARIANT_DATA_NODELETE;
+      starttime->value.variant.value.data = &server->startTime;
+      starttime->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
       UA_Server_addNode(server, (UA_Node*)starttime, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
                         nodeIdHasComponent);
       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME),
@@ -977,8 +975,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
       currenttime->value.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
                                                        .write = UA_NULL};
       UA_Server_addNode(server, (UA_Node*)currenttime,
-                        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-                        nodeIdHasComponent);
+                        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME),
                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
 
@@ -987,9 +984,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
       *stateEnum = UA_SERVERSTATE_RUNNING;
       copyNames((UA_Node*)state, "State");
       state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
-      state->value.variant.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
-      state->value.variant.arrayLength = -1;
-      state->value.variant.data = stateEnum; // points into the other object.
+      state->value.variant.value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
+      state->value.variant.value.arrayLength = -1;
+      state->value.variant.value.data = stateEnum; // points into the other object.
       UA_Server_addNode(server, (UA_Node*)state, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
                         nodeIdHasComponent);
       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE),
@@ -998,36 +995,33 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
       UA_VariableNode *buildinfo = UA_VariableNode_new();
        copyNames((UA_Node*)buildinfo, "BuildInfo");
        buildinfo->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO);
-       buildinfo->value.variant.data = UA_BuildInfo_new();
-       buildinfo->value.variant.type = &UA_TYPES[UA_TYPES_BUILDINFO];
-       getBulidInfo(server, (UA_BuildInfo*)buildinfo->value.variant.data);
+       buildinfo->value.variant.value.data = UA_BuildInfo_new();
+       buildinfo->value.variant.value.type = &UA_TYPES[UA_TYPES_BUILDINFO];
+       getBulidInfo(server, (UA_BuildInfo*)buildinfo->value.variant.value.data);
        UA_Server_addNode(server, (UA_Node*)buildinfo,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-                         nodeIdHasComponent);
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
        UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
                               nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BUILDINFOTYPE));
 
        UA_VariableNode *producturi = UA_VariableNode_new();
        copyNames((UA_Node*)producturi, "ProductUri");
        producturi->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI);
-       producturi->value.variant.data = UA_String_new();
-       *((UA_String*)producturi->value.variant.data) = UA_STRING_ALLOC(PRODUCT_URI);
-       producturi->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       producturi->value.variant.value.data = UA_String_new();
+       *((UA_String*)producturi->value.variant.value.data) = UA_STRING_ALLOC(PRODUCT_URI);
+       producturi->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
        UA_Server_addNode(server, (UA_Node*)producturi,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
-                         nodeIdHasComponent);
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
        UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI),
                               nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *manufacturername = UA_VariableNode_new();
        copyNames((UA_Node*)manufacturername, "ManufacturererName");
        manufacturername->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME);
-       manufacturername->value.variant.data = UA_String_new();
-       *((UA_String*)manufacturername->value.variant.data) = UA_STRING_ALLOC(MANUFACTURER_NAME);
-       manufacturername->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       manufacturername->value.variant.value.data = UA_String_new();
+       *((UA_String*)manufacturername->value.variant.value.data) = UA_STRING_ALLOC(MANUFACTURER_NAME);
+       manufacturername->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
        UA_Server_addNode(server, (UA_Node*)manufacturername,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
-                         nodeIdHasComponent);
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
        UA_Server_addReference(server,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
                               nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
@@ -1035,24 +1029,22 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        UA_VariableNode *productname = UA_VariableNode_new();
        copyNames((UA_Node*)productname, "ProductName");
        productname->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME);
-       productname->value.variant.data = UA_String_new();
-       *((UA_String*)productname->value.variant.data) = UA_STRING_ALLOC(PRODUCT_NAME);
-       productname->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       productname->value.variant.value.data = UA_String_new();
+       *((UA_String*)productname->value.variant.value.data) = UA_STRING_ALLOC(PRODUCT_NAME);
+       productname->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
        UA_Server_addNode(server, (UA_Node*)productname,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
-                         nodeIdHasComponent);
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
        UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
                               nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *softwareversion = UA_VariableNode_new();
        copyNames((UA_Node*)softwareversion, "SoftwareVersion");
        softwareversion->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION);
-       softwareversion->value.variant.data = UA_String_new();
-       *((UA_String*)softwareversion->value.variant.data) = UA_STRING_ALLOC(SOFTWARE_VERSION);
-       softwareversion->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       softwareversion->value.variant.value.data = UA_String_new();
+       *((UA_String*)softwareversion->value.variant.value.data) = UA_STRING_ALLOC(SOFTWARE_VERSION);
+       softwareversion->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
        UA_Server_addNode(server, (UA_Node*)softwareversion,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
-                         nodeIdHasComponent);
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
        UA_Server_addReference(server,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
                               nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
@@ -1060,32 +1052,30 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        UA_VariableNode *buildnumber = UA_VariableNode_new();
        copyNames((UA_Node*)buildnumber, "BuildNumber");
        buildnumber->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER);
-       buildnumber->value.variant.data = UA_String_new();
-       *((UA_String*)buildnumber->value.variant.data) = UA_STRING_ALLOC(BUILD_NUMBER);
-       buildnumber->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       buildnumber->value.variant.value.data = UA_String_new();
+       *((UA_String*)buildnumber->value.variant.value.data) = UA_STRING_ALLOC(BUILD_NUMBER);
+       buildnumber->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
        UA_Server_addNode(server, (UA_Node*)buildnumber,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
-                         nodeIdHasComponent);
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
        UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
                               nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *builddate = UA_VariableNode_new();
        copyNames((UA_Node*)builddate, "BuildDate");
        builddate->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE);
-       builddate->value.variant.storageType = UA_VARIANT_DATA_NODELETE;
-       builddate->value.variant.data = &server->buildDate;
-       builddate->value.variant.type = &UA_TYPES[UA_TYPES_DATETIME];
+       builddate->value.variant.value.storageType = UA_VARIANT_DATA_NODELETE;
+       builddate->value.variant.value.data = &server->buildDate;
+       builddate->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
        UA_Server_addNode(server, (UA_Node*)builddate,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
-                         nodeIdHasComponent);
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
        UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
                               nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *secondstillshutdown = UA_VariableNode_new();
        copyNames((UA_Node*)secondstillshutdown, "SecondsTillShutdown");
        secondstillshutdown->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN);
-       secondstillshutdown->value.variant.data = UA_UInt32_new();
-       secondstillshutdown->value.variant.type = &UA_TYPES[UA_TYPES_UINT32];
+       secondstillshutdown->value.variant.value.data = UA_UInt32_new();
+       secondstillshutdown->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT32];
        UA_Server_addNode(server, (UA_Node*)secondstillshutdown,
                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
        UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN),
@@ -1094,8 +1084,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        UA_VariableNode *shutdownreason = UA_VariableNode_new();
        copyNames((UA_Node*)shutdownreason, "ShutdownReason");
        shutdownreason->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON);
-       shutdownreason->value.variant.data = UA_LocalizedText_new();
-       shutdownreason->value.variant.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
+       shutdownreason->value.variant.value.data = UA_LocalizedText_new();
+       shutdownreason->value.variant.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
        UA_Server_addNode(server, (UA_Node*)shutdownreason,
                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
        UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON),

+ 0 - 755
src/server/ua_server_addressspace.c

@@ -1,755 +0,0 @@
-#include "ua_server.h"
-#include "ua_services.h"
-#include "ua_server_internal.h"
-
-UA_StatusCode UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId) {
-  union nodeUnion {
-    const UA_Node *delNodeConst;
-    UA_Node *delNode;
-  } ptrs;
-  ptrs.delNodeConst = UA_NodeStore_get(server->nodestore, &nodeId);
-  
-  if (!ptrs.delNodeConst)
-    return UA_STATUSCODE_BADNODEIDINVALID;
-  UA_NodeStore_release(ptrs.delNodeConst);
-  
-  // Remove the node from the hashmap/slot
-  UA_NodeStore_remove(server->nodestore, &nodeId);
-  
-  /* 
-   * FIXME: Delete unreachable child nodes???
-   */
-  
-  return UA_STATUSCODE_GOOD;
-}
-
-UA_StatusCode UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
-                                             UA_NodeIteratorCallback callback, void *handle) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
-    if(!parent)
-        return UA_STATUSCODE_BADNODEIDINVALID;
-    
-    for(int i=0; i<parent->referencesSize; i++) {
-        UA_ReferenceNode *ref = &parent->references[i];
-        retval |= callback(ref->targetId.nodeId, ref->isInverse, ref->referenceTypeId, handle);
-    }
-    
-    UA_NodeStore_release(parent);
-    return retval;
-}
-
-UA_StatusCode
-UA_Server_addVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                          const UA_LocalizedText displayName, const UA_LocalizedText description,
-                          const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                          UA_Variant *value, UA_NodeId *createdNodeId) {
-    UA_VariableNode *node = UA_VariableNode_new();
-    UA_StatusCode retval;
-    node->value.variant = *value; // copy content
-    UA_NodeId_copy(&nodeId, &node->nodeId);
-    UA_QualifiedName_copy(&browseName, &node->browseName);
-    UA_LocalizedText_copy(&displayName, &node->displayName);
-    UA_LocalizedText_copy(&description, &node->description);
-    node->writeMask = writeMask;
-    node->userWriteMask = userWriteMask;
-    UA_ExpandedNodeId parentId;
-    UA_ExpandedNodeId_init(&parentId);
-    UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
-    UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
-                                                         parentId, referenceTypeId);
-    UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                           UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric));
-    
-    if(res.statusCode != UA_STATUSCODE_GOOD) {
-        UA_Variant_init(&node->value.variant);
-        UA_VariableNode_delete(node);
-    } else 
-        UA_free(value);
-    retval = res.statusCode;
-    if (createdNodeId != UA_NULL)
-      UA_NodeId_copy(&res.addedNodeId, createdNodeId);
-    UA_AddNodesResult_deleteMembers(&res);
-    UA_ExpandedNodeId_deleteMembers(&parentId);
-    return retval;
-}
-
-UA_StatusCode
-UA_Server_addObjectNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                        const UA_LocalizedText displayName, const UA_LocalizedText description,
-                        const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                        const UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId){
-    UA_ObjectNode *node = UA_ObjectNode_new();
-    UA_StatusCode retval;
-    
-    UA_NodeId_copy(&nodeId, &node->nodeId);
-    UA_QualifiedName_copy(&browseName, &node->browseName);
-    UA_LocalizedText_copy(&displayName, &node->displayName);
-    UA_LocalizedText_copy(&description, &node->description);
-    node->writeMask = writeMask;
-    node->userWriteMask = userWriteMask;
-    UA_ExpandedNodeId parentId; // we need an expandednodeid
-    UA_ExpandedNodeId_init(&parentId);
-    UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
-    UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
-                                                         parentId, referenceTypeId);
-    if(res.statusCode != UA_STATUSCODE_GOOD)
-        UA_ObjectNode_delete(node);
-    retval = res.statusCode;
-    if (createdNodeId != UA_NULL)
-      UA_NodeId_copy(&res.addedNodeId, createdNodeId);
-    UA_AddNodesResult_deleteMembers(&res);
-
-    if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
-      UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
-    }
-    return retval;
-}
-
-UA_StatusCode
-UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                                    const UA_LocalizedText displayName, const UA_LocalizedText description,
-                                    const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                                    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                                    const UA_DataSource dataSource, UA_NodeId *createdNodeId) {
-    UA_VariableNode *node = UA_VariableNode_new();
-    UA_StatusCode retval;
-    
-    node->valueSource = UA_VALUESOURCE_DATASOURCE;
-    node->value.dataSource = dataSource;
-    UA_NodeId_copy(&nodeId, &node->nodeId);
-    UA_QualifiedName_copy(&browseName, &node->browseName);
-    UA_LocalizedText_copy(&displayName, &node->displayName);
-    UA_LocalizedText_copy(&description, &node->description);
-    node->writeMask = writeMask;
-    node->userWriteMask = userWriteMask;
-    UA_ExpandedNodeId parentId; // dummy exapndednodeid
-    UA_ExpandedNodeId_init(&parentId);
-    UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
-    UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
-                                                         parentId, referenceTypeId);
-    UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
-    if(res.statusCode != UA_STATUSCODE_GOOD)
-        UA_VariableNode_delete(node);
-    retval = res.statusCode;
-    if (createdNodeId != UA_NULL)
-      UA_NodeId_copy(&res.addedNodeId, createdNodeId);
-    UA_AddNodesResult_deleteMembers(&res);
-    return retval;
-}
-
-                                    
-UA_StatusCode
-UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                              const UA_LocalizedText displayName, const UA_LocalizedText description,
-                              const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                              UA_Variant *value, const UA_Int32 valueRank, const UA_Boolean isAbstract,
-                              UA_NodeId *createdNodeId) {
-    UA_VariableTypeNode *node = UA_VariableTypeNode_new();
-    UA_StatusCode retval;
-    node->value.variant = *value; // copy content
-    UA_NodeId_copy(&nodeId, &node->nodeId);
-    UA_QualifiedName_copy(&browseName, &node->browseName);
-    UA_LocalizedText_copy(&displayName, &node->displayName);
-    UA_LocalizedText_copy(&description, &node->description);
-    node->writeMask = writeMask;
-    node->userWriteMask = userWriteMask;
-    UA_ExpandedNodeId parentId;
-    UA_ExpandedNodeId_init(&parentId);
-    UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
-    node->isAbstract = isAbstract;
-    node->valueRank  = valueRank;
-    UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
-                                                         parentId, referenceTypeId);
-    UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                           UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric));
-    
-    if(res.statusCode != UA_STATUSCODE_GOOD) {
-        UA_Variant_init(&node->value.variant);
-        UA_VariableTypeNode_delete(node);
-    } else 
-        UA_free(value);
-    retval = res.statusCode;
-    if (createdNodeId != UA_NULL)
-      UA_NodeId_copy(&res.addedNodeId, createdNodeId);
-    UA_AddNodesResult_deleteMembers(&res);
-    return retval ;
-}
-
-UA_StatusCode
-UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                          const UA_LocalizedText displayName, const UA_LocalizedText description,
-                          const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                          const UA_ExpandedNodeId typeDefinition, const UA_Boolean isAbstract,
-                          UA_NodeId *createdNodeId) {
-  UA_DataTypeNode *node = UA_DataTypeNode_new();
-  UA_StatusCode retval;
-  
-  UA_NodeId_copy(&nodeId, &node->nodeId);
-  UA_QualifiedName_copy(&browseName, &node->browseName);
-  UA_LocalizedText_copy(&displayName, &node->displayName);
-  UA_LocalizedText_copy(&description, &node->description);
-  node->writeMask = writeMask;
-  node->userWriteMask = userWriteMask;
-  UA_ExpandedNodeId parentId; // we need an expandednodeid
-  UA_ExpandedNodeId_init(&parentId);
-  UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
-  node->isAbstract = isAbstract;
-  UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
-                                                       parentId, referenceTypeId);
-  if(res.statusCode != UA_STATUSCODE_GOOD)
-    UA_DataTypeNode_delete(node);
-  retval = res.statusCode;
-  if (createdNodeId != UA_NULL)
-    UA_NodeId_copy(&res.addedNodeId, createdNodeId);
-  UA_AddNodesResult_deleteMembers(&res);
-  
-  if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
-    UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
-  }
-  
-  return retval;
-}
-
-UA_StatusCode
-UA_Server_addViewNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                      const UA_LocalizedText displayName, const UA_LocalizedText description,
-                      const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                      const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                      const UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId) {
-  UA_ViewNode *node = UA_ViewNode_new();
-  UA_StatusCode retval;
-  
-  UA_NodeId_copy(&nodeId, &node->nodeId);
-  UA_QualifiedName_copy(&browseName, &node->browseName);
-  UA_LocalizedText_copy(&displayName, &node->displayName);
-  UA_LocalizedText_copy(&description, &node->description);
-  node->writeMask = writeMask;
-  node->userWriteMask = userWriteMask;
-  UA_ExpandedNodeId parentId; // we need an expandednodeid
-  UA_ExpandedNodeId_init(&parentId);
-  UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
-  node->containsNoLoops = UA_TRUE;
-  node->eventNotifier = 0;
-  UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
-                                                       parentId, referenceTypeId);
-  if(res.statusCode != UA_STATUSCODE_GOOD)
-    UA_ViewNode_delete(node);
-  retval = res.statusCode;
-  if (createdNodeId != UA_NULL)
-    UA_NodeId_copy(&res.addedNodeId, createdNodeId);
-  UA_AddNodesResult_deleteMembers(&res);
-  
-  if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
-    UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
-  }
-  
-  return retval;
-}
-
-UA_StatusCode UA_Server_addReferenceTypeNode (UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                                              const UA_LocalizedText displayName, const UA_LocalizedText description,
-                                              const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                                              const UA_ExpandedNodeId typeDefinition, const UA_LocalizedText inverseName,
-                                              UA_NodeId *createdNodeId) {
-  UA_ReferenceTypeNode *node = UA_ReferenceTypeNode_new();
-  UA_StatusCode retval;
-  
-  UA_NodeId_copy(&nodeId, &node->nodeId);
-  UA_QualifiedName_copy(&browseName, &node->browseName);
-  UA_LocalizedText_copy(&displayName, &node->displayName);
-  UA_LocalizedText_copy(&description, &node->description);
-  UA_LocalizedText_copy(&inverseName, &node->inverseName);
-  node->writeMask = writeMask;
-  node->userWriteMask = userWriteMask;
-  UA_ExpandedNodeId parentId; // we need an expandednodeid
-  UA_ExpandedNodeId_init(&parentId);
-  UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
-  UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
-                                                       parentId, referenceTypeId);
-  if(res.statusCode != UA_STATUSCODE_GOOD)
-    UA_ReferenceTypeNode_delete(node);
-  retval = res.statusCode;
-  if (createdNodeId != UA_NULL)
-    UA_NodeId_copy(&res.addedNodeId, createdNodeId);
-  UA_AddNodesResult_deleteMembers(&res);
-  
-  if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
-    UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
-  }
-  
-  return retval;
-}
-
-UA_StatusCode UA_Server_addObjectTypeNode (UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                                           const UA_LocalizedText displayName, const UA_LocalizedText description,
-                                           const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                                           const UA_ExpandedNodeId typeDefinition, const UA_Boolean isAbstract,
-                                           UA_NodeId *createdNodeId) {
-  UA_ObjectTypeNode *node = UA_ObjectTypeNode_new();
-  UA_StatusCode retval;
-  
-  UA_NodeId_copy(&nodeId, &node->nodeId);
-  UA_QualifiedName_copy(&browseName, &node->browseName);
-  UA_LocalizedText_copy(&displayName, &node->displayName);
-  UA_LocalizedText_copy(&description, &node->description);
-  node->writeMask = writeMask;
-  node->userWriteMask = userWriteMask;
-  UA_ExpandedNodeId parentId; // we need an expandednodeid
-  UA_ExpandedNodeId_init(&parentId);
-  UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
-  node->isAbstract = isAbstract;
-  UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
-                                                       parentId, referenceTypeId);
-  if(res.statusCode != UA_STATUSCODE_GOOD)
-    UA_ObjectTypeNode_delete(node);
-  retval = res.statusCode;
-  if (createdNodeId != UA_NULL)
-    UA_NodeId_copy(&res.addedNodeId, createdNodeId);
-  UA_AddNodesResult_deleteMembers(&res);
-  
-  if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
-    UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
-  }
-  
-  return retval;
-}
-
-/* Userspace Version of addOneWayReferenceWithSession*/
-UA_StatusCode
-UA_Server_addMonodirectionalReference(UA_Server *server, UA_NodeId sourceNodeId, UA_ExpandedNodeId targetNodeId,
-                                      UA_NodeId referenceTypeId, UA_Boolean isforward) {
-    UA_AddReferencesItem ref;
-    UA_AddReferencesItem_init(&ref);
-    UA_StatusCode retval = UA_NodeId_copy(&sourceNodeId, &ref.sourceNodeId);
-    retval |= UA_ExpandedNodeId_copy(&targetNodeId, &ref.targetNodeId);
-    retval |= UA_NodeId_copy(&referenceTypeId, &ref.referenceTypeId);
-    if(retval != UA_STATUSCODE_GOOD)
-        goto cleanup;
-    
-    const UA_Node *target = UA_NodeStore_get(server->nodestore, &ref.targetNodeId.nodeId);
-    if(!target) {
-        retval = UA_STATUSCODE_BADNODEIDINVALID;
-        goto cleanup;
-    }
-
-    if(isforward == UA_TRUE)
-        ref.isForward = UA_TRUE;
-    ref.targetNodeClass = target->nodeClass;
-    UA_NodeStore_release(target);
-    retval = addOneWayReferenceWithSession(server, (UA_Session *) UA_NULL, &ref);
-
- cleanup:
-    UA_AddReferencesItem_deleteMembers(&ref);
-    return retval;
-}
-    
-
-/* Adds a one-way reference to the local nodestore */
-UA_StatusCode
-addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) {
-    const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
-    if(!node)
-        return UA_STATUSCODE_BADINTERNALERROR;
-	UA_StatusCode retval = UA_STATUSCODE_GOOD;
-#ifndef UA_MULTITHREADING
-	size_t i = node->referencesSize;
-	if(node->referencesSize < 0)
-		i = 0;
-    size_t refssize = (i+1) | 3; // so the realloc is not necessary every time
-	UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize);
-	if(!new_refs)
-		retval = UA_STATUSCODE_BADOUTOFMEMORY;
-	else {
-		UA_ReferenceNode_init(&new_refs[i]);
-		retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId);
-		new_refs[i].isInverse = !item->isForward;
-		retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId);
-		/* hack. be careful! possible only in the single-threaded case. */
-		UA_Node *mutable_node = (UA_Node*)(uintptr_t)node;
-		mutable_node->references = new_refs;
-		if(retval != UA_STATUSCODE_GOOD) {
-			UA_NodeId_deleteMembers(&new_refs[node->referencesSize].referenceTypeId);
-			UA_ExpandedNodeId_deleteMembers(&new_refs[node->referencesSize].targetId);
-		} else
-			mutable_node->referencesSize = i+1;
-	}
-	UA_NodeStore_release(node);
-	return retval;
-#else
-    UA_Node *newNode = UA_NULL;
-    void (*deleteNode)(UA_Node*) = UA_NULL;
-    switch(node->nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        newNode = (UA_Node*)UA_ObjectNode_new();
-        UA_ObjectNode_copy((const UA_ObjectNode*)node, (UA_ObjectNode*)newNode);
-        deleteNode = (void (*)(UA_Node*))UA_ObjectNode_delete;
-        break;
-    case UA_NODECLASS_VARIABLE:
-        newNode = (UA_Node*)UA_VariableNode_new();
-        UA_VariableNode_copy((const UA_VariableNode*)node, (UA_VariableNode*)newNode);
-        deleteNode = (void (*)(UA_Node*))UA_VariableNode_delete;
-        break;
-    case UA_NODECLASS_METHOD:
-        newNode = (UA_Node*)UA_MethodNode_new();
-        UA_MethodNode_copy((const UA_MethodNode*)node, (UA_MethodNode*)newNode);
-        deleteNode = (void (*)(UA_Node*))UA_MethodNode_delete;
-        break;
-    case UA_NODECLASS_OBJECTTYPE:
-        newNode = (UA_Node*)UA_ObjectTypeNode_new();
-        UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)node, (UA_ObjectTypeNode*)newNode);
-        deleteNode = (void (*)(UA_Node*))UA_ObjectTypeNode_delete;
-        break;
-    case UA_NODECLASS_VARIABLETYPE:
-        newNode = (UA_Node*)UA_VariableTypeNode_new();
-        UA_VariableTypeNode_copy((const UA_VariableTypeNode*)node, (UA_VariableTypeNode*)newNode);
-        deleteNode = (void (*)(UA_Node*))UA_VariableTypeNode_delete;
-        break;
-    case UA_NODECLASS_REFERENCETYPE:
-        newNode = (UA_Node*)UA_ReferenceTypeNode_new();
-        UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)node, (UA_ReferenceTypeNode*)newNode);
-        deleteNode = (void (*)(UA_Node*))UA_ReferenceTypeNode_delete;
-        break;
-    case UA_NODECLASS_DATATYPE:
-        newNode = (UA_Node*)UA_DataTypeNode_new();
-        UA_DataTypeNode_copy((const UA_DataTypeNode*)node, (UA_DataTypeNode*)newNode);
-        deleteNode = (void (*)(UA_Node*))UA_DataTypeNode_delete;
-        break;
-    case UA_NODECLASS_VIEW:
-        newNode = (UA_Node*)UA_ViewNode_new();
-        UA_ViewNode_copy((const UA_ViewNode*)node, (UA_ViewNode*)newNode);
-        deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete;
-        break;
-    default:
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
-
-    UA_Int32 count = node->referencesSize;
-    if(count < 0)
-        count = 0;
-    UA_ReferenceNode *old_refs = newNode->references;
-    UA_ReferenceNode *new_refs = UA_malloc(sizeof(UA_ReferenceNode)*(count+1));
-    if(!new_refs) {
-        deleteNode(newNode);
-        UA_NodeStore_release(node);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    }
-
-    // insert the new reference
-    UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
-    UA_ReferenceNode_init(&new_refs[count]);
-    retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
-    new_refs[count].isInverse = !item->isForward;
-    retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_Array_delete(new_refs, &UA_TYPES[UA_TYPES_REFERENCENODE], ++count);
-        newNode->references = UA_NULL;
-        newNode->referencesSize = 0;
-        deleteNode(newNode);
-        UA_NodeStore_release(node);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    }
-
-    UA_free(old_refs);
-    newNode->references = new_refs;
-    newNode->referencesSize = ++count;
-    retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL);
-	UA_NodeStore_release(node);
-	if(retval == UA_STATUSCODE_BADINTERNALERROR) {
-		/* presumably because the node was replaced and an old version was updated at the same time.
-           just try again */
-		deleteNode(newNode);
-		return addOneWayReferenceWithSession(server, session, item);
-	}
-	return retval;
-#endif
-}
-
-UA_StatusCode deleteOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_DeleteReferencesItem *item) {
-    const UA_Node *orig;
- repeat_deleteref_oneway:
-    orig = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
-    if(!orig)
-        return UA_STATUSCODE_BADNODEIDUNKNOWN;
-
-#ifndef UA_MULTITHREADING
-    /* We cheat if multithreading is not enabled and treat the node as mutable. */
-    UA_Node *editable = (UA_Node*)(uintptr_t)orig;
-#else
-    UA_Node *editable = UA_Node_copyAnyNodeClass(orig);
-    UA_Boolean edited = UA_FALSE;;
-#endif
-
-    for(UA_Int32 i = editable->referencesSize - 1; i >= 0; i--) {
-        if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &editable->references[i].targetId.nodeId))
-            continue;
-        if(!UA_NodeId_equal(&item->referenceTypeId, &editable->references[i].referenceTypeId))
-            continue;
-        if(item->isForward == editable->references[i].isInverse)
-            continue;
-        /* move the last entry to override the current position */
-        UA_ReferenceNode_deleteMembers(&editable->references[i]);
-        editable->references[i] = editable->references[editable->referencesSize-1];
-        editable->referencesSize--;
-
-#ifdef UA_MULTITHREADING
-        edited = UA_TRUE;
-#endif
-    }
-
-    /* we removed the last reference */
-    if(editable->referencesSize <= 0 && editable->references)
-        UA_free(editable->references);
-    
-#ifdef UA_MULTITHREADING
-    if(!edited) {
-        UA_Node_deleteAnyNodeClass(editable);
-    } else if(UA_NodeStore_replace(server->nodestore, orig, editable, UA_NULL) != UA_STATUSCODE_GOOD) {
-        /* the node was changed by another thread. repeat. */
-        UA_Node_deleteAnyNodeClass(editable);
-        UA_NodeStore_release(orig);
-        goto repeat_deleteref_oneway;
-    }
-#endif
-
-    UA_NodeStore_release(orig);
-    return UA_STATUSCODE_GOOD;;
-}
-
-/* userland version of addReferenceWithSession */
-UA_StatusCode UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
-                                     const UA_ExpandedNodeId targetId) {
-    UA_AddReferencesItem item;
-    UA_AddReferencesItem_init(&item);
-    item.sourceNodeId = sourceId;
-    item.referenceTypeId = refTypeId;
-    item.isForward = UA_TRUE;
-    item.targetNodeId = targetId;
-    return UA_Server_addReferenceWithSession(server, &adminSession, &item);
-}
-
-UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session,
-                                                const UA_AddReferencesItem *item) {
-    if(item->targetServerUri.length > 0)
-        return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
-
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-
-#ifdef UA_EXTERNAL_NAMESPACES
-    UA_ExternalNodeStore *ensFirst = UA_NULL;
-    UA_ExternalNodeStore *ensSecond = UA_NULL;
-    for(size_t j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
-        if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index)
-            ensFirst = &server->externalNamespaces[j].externalNodeStore;
-        if(item->targetNodeId.nodeId.namespaceIndex == server->externalNamespaces[j].index)
-            ensSecond = &server->externalNamespaces[j].externalNodeStore;
-    }
-
-    if(ensFirst) {
-        // todo: use external nodestore
-    } else
-#endif
-        retval = addOneWayReferenceWithSession(server, session, item);
-
-    if(retval)
-        return retval;
-
-    UA_AddReferencesItem secondItem;
-    secondItem = *item;
-    secondItem.targetNodeId.nodeId = item->sourceNodeId;
-    secondItem.sourceNodeId = item->targetNodeId.nodeId;
-    secondItem.isForward = !item->isForward;
-#ifdef UA_EXTERNAL_NAMESPACES
-    if(ensSecond) {
-        // todo: use external nodestore
-    } else
-#endif
-        retval = addOneWayReferenceWithSession (server, session, &secondItem);
-
-    // todo: remove reference if the second direction failed
-    return retval;
-} 
-
-UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId parentNodeId,
-                                    const UA_NodeId referenceTypeId) {
-    return UA_Server_addNodeWithSession(server, &adminSession, node, parentNodeId, referenceTypeId);
-}
-
-UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
-                                               const UA_ExpandedNodeId parentNodeId, const UA_NodeId referenceTypeId) {
-    UA_AddNodesResult result;
-    UA_AddNodesResult_init(&result);
-
-    if(node->nodeId.namespaceIndex >= server->namespacesSize) {
-        result.statusCode = UA_STATUSCODE_BADNODEIDINVALID;
-        return result;
-    }
-
-    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId.nodeId);
-    if(!parent) {
-        result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
-        return result;
-    }
-
-    const UA_ReferenceTypeNode *referenceType =
-        (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, &referenceTypeId);
-    if(!referenceType) {
-        result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
-        goto ret;
-    }
-
-    if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
-        result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
-        goto ret2;
-    }
-
-    if(referenceType->isAbstract == UA_TRUE) {
-        result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
-        goto ret2;
-    }
-
-    // todo: test if the referencetype is hierarchical
-    //FIXME: a bit dirty workaround of preserving namespace
-    //namespace index is assumed to be valid
-    const UA_Node *managed = UA_NULL;
-    UA_NodeId tempNodeid;
-    UA_NodeId_init(&tempNodeid);
-    UA_NodeId_copy(&node->nodeId, &tempNodeid);
-    tempNodeid.namespaceIndex = 0;
-    if(UA_NodeId_isNull(&tempNodeid)) {
-        if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
-            result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-            goto ret2;
-        }
-        result.addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric
-    } else {
-        if(UA_NodeId_copy(&node->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
-            result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-            goto ret2;
-        }
-
-        if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
-            result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS;  // todo: differentiate out of memory
-            UA_NodeId_deleteMembers(&result.addedNodeId);
-            goto ret2;
-        }
-    }
-    
-    // reference back to the parent
-    UA_AddReferencesItem item;
-    UA_AddReferencesItem_init(&item);
-    item.sourceNodeId = managed->nodeId;
-    item.referenceTypeId = referenceType->nodeId;
-    item.isForward = UA_FALSE;
-    item.targetNodeId.nodeId = parent->nodeId;
-    UA_Server_addReferenceWithSession(server, session, &item);
-
-    // todo: error handling. remove new node from nodestore
-    UA_NodeStore_release(managed);
-    
- ret2:
-    UA_NodeId_deleteMembers(&tempNodeid);
-    UA_NodeStore_release((const UA_Node*)referenceType);
- ret:
-    UA_NodeStore_release(parent);
-    return result;
-}
-
-#ifdef ENABLE_METHODCALLS
-UA_StatusCode
-UA_Server_addMethodNode(UA_Server* server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                        UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId, 
-                        const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask, 
-                        UA_MethodCallback method, void *handle, UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments, 
-                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments, 
-                        UA_NodeId* createdNodeId) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_MethodNode *newMethod = UA_MethodNode_new();
-    UA_NodeId_copy(&nodeId, &newMethod->nodeId);
-    UA_QualifiedName_copy(&browseName, &newMethod->browseName);
-    UA_LocalizedText_copy(&displayName, &newMethod->displayName);
-    UA_LocalizedText_copy(&description, &newMethod->description);
-    newMethod->writeMask = writeMask;
-    newMethod->userWriteMask = userWriteMask;
-    newMethod->attachedMethod = method;
-    newMethod->methodHandle   = handle;
-    newMethod->executable = UA_TRUE;
-    newMethod->userExecutable = UA_TRUE;
-    
-    UA_ExpandedNodeId parentExpandedNodeId;
-    UA_ExpandedNodeId_init(&parentExpandedNodeId);
-    UA_NodeId_copy(&parentNodeId, &parentExpandedNodeId.nodeId);
-    UA_AddNodesResult addRes = UA_Server_addNode(server, (UA_Node*)newMethod, parentExpandedNodeId, referenceTypeId);
-    retval |= addRes.statusCode;
-    if(retval!= UA_STATUSCODE_GOOD) {
-        UA_MethodNode_delete(newMethod);
-        return retval;
-    }
-    
-    UA_ExpandedNodeId methodExpandedNodeId;
-    UA_ExpandedNodeId_init(&methodExpandedNodeId);
-    UA_NodeId_copy(&addRes.addedNodeId, &methodExpandedNodeId.nodeId);
-    
-    if (createdNodeId != UA_NULL)
-      UA_NodeId_copy(&addRes.addedNodeId, createdNodeId);
-    UA_AddNodesResult_deleteMembers(&addRes);
-    
-    /* Only proceed with creating in/outputArguments if the method and both arguments are not
-     * UA_NULL; otherwise this is a pretty strong indicator that this node was generated,
-     * in which case these arguments will be created later and individually.
-     */
-    if (method == UA_NULL && inputArguments == UA_NULL && outputArguments == UA_NULL &&
-        inputArgumentsSize == 0 && outputArgumentsSize == 0)
-      return retval;
-    
-    /* create InputArguments */
-    UA_NodeId argId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0); 
-    UA_VariableNode *inputArgumentsVariableNode  = UA_VariableNode_new();
-    retval |= UA_NodeId_copy(&argId, &inputArgumentsVariableNode->nodeId);
-    inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
-    inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-    inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-    inputArgumentsVariableNode->valueRank = 1;
-    UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant, inputArguments,
-                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-    addRes = UA_Server_addNode(server, (UA_Node*)inputArgumentsVariableNode, methodExpandedNodeId,
-                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
-    if(addRes.statusCode != UA_STATUSCODE_GOOD) {
-        UA_ExpandedNodeId_deleteMembers(&methodExpandedNodeId);
-        if(createdNodeId != UA_NULL)
-            UA_NodeId_deleteMembers(createdNodeId);    	
-        // TODO Remove node
-        return addRes.statusCode;
-    }
-    UA_AddNodesResult_deleteMembers(&addRes);
-
-    /* create OutputArguments */
-    argId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0);
-    UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
-    retval |= UA_NodeId_copy(&argId, &outputArgumentsVariableNode->nodeId);
-    outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
-    outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-    outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-    outputArgumentsVariableNode->valueRank = 1;
-    UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant, outputArguments,
-                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-    addRes = UA_Server_addNode(server, (UA_Node*)outputArgumentsVariableNode, methodExpandedNodeId,
-                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
-    UA_ExpandedNodeId_deleteMembers(&methodExpandedNodeId);
-    if(addRes.statusCode != UA_STATUSCODE_GOOD) {
-        if(createdNodeId != UA_NULL)
-            UA_NodeId_deleteMembers(createdNodeId);    	
-        // TODO Remove node
-        retval = addRes.statusCode;
-    }
-    UA_AddNodesResult_deleteMembers(&addRes);
-    return retval;
-}
-#endif

+ 22 - 29
src/server/ua_server_binary.c

@@ -42,18 +42,18 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size
     ackHeader.messageSize =  8 + 20; /* ackHeader + ackMessage */
 
     UA_ByteString ack_msg;
-    if(connection->getBuffer(connection, &ack_msg) != UA_STATUSCODE_GOOD)
+    if(connection->getSendBuffer(connection, connection->remoteConf.recvBufferSize,
+                                 &ack_msg) != UA_STATUSCODE_GOOD)
         return;
 
     size_t tmpPos = 0;
     UA_TcpMessageHeader_encodeBinary(&ackHeader, &ack_msg, &tmpPos);
     UA_TcpAcknowledgeMessage_encodeBinary(&ackMessage, &ack_msg, &tmpPos);
-    if(connection->write(connection, &ack_msg, ackHeader.messageSize) != UA_STATUSCODE_GOOD)
-        connection->releaseBuffer(connection, &ack_msg);
+    ack_msg.length = ackHeader.messageSize;
+    connection->send(connection, &ack_msg);
 }
 
-static void processOPN(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg,
-                       size_t *pos) {
+static void processOPN(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) {
     if(connection->state != UA_CONNECTION_ESTABLISHED) {
         connection->close(connection);
         return;
@@ -112,7 +112,7 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
                                                UA_ENCODINGOFFSET_BINARY);
 
     UA_ByteString resp_msg;
-    retval = connection->getBuffer(connection, &resp_msg);
+    retval = connection->getSendBuffer(connection, connection->remoteConf.recvBufferSize, &resp_msg);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_OpenSecureChannelResponse_deleteMembers(&p);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
@@ -126,16 +126,14 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     retval |= UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos);
 
     if(retval != UA_STATUSCODE_GOOD) {
-        connection->releaseBuffer(connection, &resp_msg);
+        connection->releaseSendBuffer(connection, &resp_msg);
         connection->close(connection);
     } else {
         respHeader.messageHeader.messageSize = tmpPos;
         tmpPos = 0;
         UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
-
-        if(connection->write(connection, &resp_msg,
-                             respHeader.messageHeader.messageSize) != UA_STATUSCODE_GOOD)
-            connection->releaseBuffer(connection, &resp_msg);
+        resp_msg.length = respHeader.messageHeader.messageSize;
+        connection->send(connection, &resp_msg);
     }
 
     UA_OpenSecureChannelResponse_deleteMembers(&p);
@@ -173,8 +171,8 @@ static void invoke_service(UA_Server *server, UA_SecureChannel *channel, UA_UInt
         response->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
     } else if(session->activated == UA_FALSE) {
         response->serviceResult = UA_STATUSCODE_BADSESSIONNOTACTIVATED;
-        /* the session is invalidated FIXME: do this delayed*/
-        UA_SessionManager_removeSession(&server->sessionManager, server, &request->authenticationToken);
+        /* /\* the session is invalidated FIXME: do this delayed*\/ */
+        /* UA_SessionManager_removeSession(&server->sessionManager, server, &request->authenticationToken); */
     } else {
         UA_Session_updateLifetime(session);
         service(server, session, request, response);
@@ -225,21 +223,20 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     retval = UA_UInt32_decodeBinary(msg, pos, &tokenId);
     retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader);
 #ifndef EXTENSION_STATELESS
-    if(retval != UA_STATUSCODE_GOOD || tokenId==0) //0 is invalid
+    if(retval != UA_STATUSCODE_GOOD || tokenId == 0) // 0 is invalid
+        return;
 #else
     if(retval != UA_STATUSCODE_GOOD)
-#endif
         return;
+#endif
 
-    if(clientChannel != &anonymousChannel){
-        if(tokenId!=clientChannel->securityToken.tokenId){
-            //is client using a newly issued token?
-            if(tokenId==clientChannel->nextSecurityToken.tokenId){ //tokenId is not 0
-                UA_SecureChannel_revolveTokens(clientChannel);
-            }else{
-                //FIXME: how to react to this, what do we have to return? Or just kill the channel
-            }
+    if(clientChannel != &anonymousChannel && tokenId != clientChannel->securityToken.tokenId) {
+        if(tokenId != clientChannel->nextSecurityToken.tokenId) {
+            /* close the securechannel but keep the connection open */
+            Service_CloseSecureChannel(server, clientChannel->securityToken.channelId);
+            return;
         }
+        UA_SecureChannel_revolveTokens(clientChannel);
     }
 
     /* Read the request type */
@@ -415,7 +412,6 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
         }
 
         size_t targetpos = pos - 8 + tcpMessageHeader.messageSize;
-
         switch(tcpMessageHeader.messageTypeAndFinal & 0xffffff) {
         case UA_MESSAGETYPEANDFINAL_HELF & 0xffffff:
             processHEL(connection, msg, &pos);
@@ -425,18 +421,16 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             break;
         case UA_MESSAGETYPEANDFINAL_MSGF & 0xffffff:
 #ifndef EXTENSION_STATELESS
-            if(connection->state != UA_CONNECTION_ESTABLISHED){
+            if(connection->state != UA_CONNECTION_ESTABLISHED) {
                 connection->close(connection);
-                UA_ByteString_deleteMembers(msg);
                 return;
-            }else
+            } else
 #endif
                 processMSG(connection, server, msg, &pos);
             break;
         case UA_MESSAGETYPEANDFINAL_CLOF & 0xffffff:
             processCLO(connection, server, msg, &pos);
             connection->close(connection);
-            UA_ByteString_deleteMembers(msg);
             return;
         }
 
@@ -447,5 +441,4 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             pos = targetpos;
         }
     } while(msg->length > (UA_Int32)pos);
-    UA_ByteString_deleteMembers(msg);
 }

+ 1 - 1
src/server/ua_server_internal.h

@@ -38,7 +38,7 @@ struct UA_Server {
 
     /* Communication */
     size_t networkLayersSize;
-    UA_ServerNetworkLayer *networkLayers;
+    UA_ServerNetworkLayer **networkLayers;
 
     /* Security */
     UA_ByteString serverCertificate;

+ 17 - 8
src/server/ua_server_worker.c

@@ -51,15 +51,24 @@ static void processJobs(UA_Server *server, UA_Job *jobs, UA_Int32 jobsSize) {
     for (UA_Int32 i = 0; i < jobsSize; i++) {
         UA_Job *job = &jobs[i];
         switch(job->type) {
-        case UA_JOBTYPE_BINARYMESSAGE:
-            UA_Server_processBinaryMessage(server, job->job.binaryMessage.connection,
-                                           &job->job.binaryMessage.message);
+        case UA_JOBTYPE_NOTHING:
             break;
         case UA_JOBTYPE_DETACHCONNECTION:
             UA_Connection_detachSecureChannel(job->job.closeConnection);
             break;
+        case UA_JOBTYPE_BINARYMESSAGE_NETWORKLAYER:
+            UA_Server_processBinaryMessage(server, job->job.binaryMessage.connection,
+                                           &job->job.binaryMessage.message);
+            UA_Connection *connection = job->job.binaryMessage.connection;
+            connection->releaseRecvBuffer(connection, &job->job.binaryMessage.message);
+            break;
+        case UA_JOBTYPE_BINARYMESSAGE_ALLOCATED:
+            UA_Server_processBinaryMessage(server, job->job.binaryMessage.connection,
+                                           &job->job.binaryMessage.message);
+            UA_ByteString_deleteMembers(&job->job.binaryMessage.message);
+            break;
         case UA_JOBTYPE_METHODCALL:
-        case UA_JOBTYPE_DELAYEDMETHODCALL:
+        case UA_JOBTYPE_METHODCALL_DELAYED:
             job->job.methodCall.method(server, job->job.methodCall.data);
             break;
         default:
@@ -569,7 +578,7 @@ UA_StatusCode result = UA_STATUSCODE_GOOD;
 
     /* Start the networklayers */
     for(size_t i = 0; i < server->networkLayersSize; i++)
-        result |= server->networkLayers[i].start(&server->networkLayers[i], &server->logger);
+        result |= server->networkLayers[i]->start(server->networkLayers[i], server->logger);
 
     return result;
 }
@@ -584,7 +593,7 @@ UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
 
     /* Get work from the networklayer */
     for(size_t i = 0; i < server->networkLayersSize; i++) {
-        UA_ServerNetworkLayer *nl = &server->networkLayers[i];
+        UA_ServerNetworkLayer *nl = server->networkLayers[i];
         UA_Job *jobs;
         UA_Int32 jobsSize;
         if(*running) {
@@ -593,12 +602,12 @@ UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
             else
                 jobsSize = nl->getJobs(nl, &jobs, 0);
         } else
-            jobsSize = server->networkLayers[i].stop(nl, &jobs);
+            jobsSize = server->networkLayers[i]->stop(nl, &jobs);
 
 #ifdef UA_MULTITHREADING
         /* Filter out delayed work */
         for(UA_Int32 k=0;k<jobsSize;k++) {
-            if(jobs[k].type != UA_JOBTYPE_DELAYEDMETHODCALL)
+            if(jobs[k].type != UA_JOBTYPE_METHODCALL_DELAYED)
                 continue;
             addDelayedJob(server, &jobs[k]);
             jobs[k].type = UA_JOBTYPE_NOTHING;

+ 18 - 12
src/server/ua_services_attribute.c

@@ -99,28 +99,33 @@ static void handleSourceTimestamps(UA_TimestampsToReturn timestamps, UA_DataValu
 static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_TimestampsToReturn timestamps,
                                           const UA_ReadValueId *id, UA_DataValue *v) {
     UA_NumericRange range;
+    UA_NumericRange *rangeptr = UA_NULL;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_Boolean hasRange = UA_FALSE;
     if(id->indexRange.length > 0) {
         retval = parse_numericrange(id->indexRange, &range);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
-        hasRange = UA_TRUE;
+        rangeptr = &range;
     }
 
     if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-        if(hasRange)
+        if(vn->value.variant.callback.onRead)
+            vn->value.variant.callback.onRead(vn->value.variant.callback.handle, vn->nodeId,
+                                              &v->value, rangeptr);
+        if(rangeptr)
             retval = UA_Variant_copyRange(&vn->value.variant, &v->value, range);
         else
             retval = UA_Variant_copy(&vn->value.variant, &v->value);
+        if(retval == UA_STATUSCODE_GOOD)
+            handleSourceTimestamps(timestamps, v);
     } else {
         UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
                                       timestamps == UA_TIMESTAMPSTORETURN_BOTH);
         retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId,
-                                            sourceTimeStamp, &range, v);
+                                           sourceTimeStamp, &rangeptr, v);
     }
 
-    if(hasRange)
+    if(rangeptr)
         UA_free(range.dimensions);
     return retval;
 }
@@ -446,14 +451,14 @@ Service_Write_single_Value(UA_Server *server, UA_Session *session, UA_VariableNo
     UA_assert(node->valueSource == UA_VALUESOURCE_VARIANT);
 
     /* Parse the range */
-    UA_Boolean hasRange = UA_FALSE;
     UA_NumericRange range;
+    UA_NumericRange *rangeptr = UA_NULL;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(wvalue->indexRange.length > 0) {
         retval = parse_numericrange(wvalue->indexRange, &range);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
-        hasRange = UA_TRUE;
+        rangeptr = &range;
     }
 
     /* The nodeid on the wire may be != the nodeid in the node: opaque types, enums and bytestrings.
@@ -477,13 +482,13 @@ Service_Write_single_Value(UA_Server *server, UA_Session *session, UA_VariableNo
             newV->data = str->data;
             newV->type = &UA_TYPES[UA_TYPES_BYTE];
         } else {
-            if(hasRange)
+            if(rangeptr)
                 UA_free(range.dimensions);
             return UA_STATUSCODE_BADTYPEMISMATCH;
         }
     }
     
-    if(!hasRange) {
+    if(!rangeptr) {
         // TODO: Avoid copying the whole node and then delete the old value for multithreading
         UA_Variant_deleteMembers(&node->value.variant);
         node->value.variant = *newV;
@@ -491,8 +496,11 @@ Service_Write_single_Value(UA_Server *server, UA_Session *session, UA_VariableNo
     } else {
         retval = UA_Variant_setRangeCopy(&node->value.variant, newV->data, newV->arrayLength, range);
     }
+    if(node->value.variant.callback.onWrite)
+        node->value.variant.callback.onWrite(node->value.variant.callback.handle, node->nodeId,
+                                             &node->value.variant.value, rangeptr);
 
-    if(hasRange)
+    if(rangeptr)
         UA_free(range.dimensions);
     return retval;
 }
@@ -632,9 +640,7 @@ UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_Wr
         UA_Node_deleteAnyNodeClass(copy);
         return retval;
     }
-#endif
        
-#ifdef UA_MULTITHREADING
     retval = UA_NodeStore_replace(server->nodestore, orig, copy, UA_NULL);
 	UA_NodeStore_release(orig);
     if(retval != UA_STATUSCODE_GOOD) {

+ 10 - 10
src/server/ua_services_call.c

@@ -73,12 +73,12 @@ static UA_StatusCode statisfySignature(UA_Variant *var, UA_Argument arg) {
 }
 
 static UA_StatusCode argConformsToDefinition(UA_CallMethodRequest *rs, const UA_VariableNode *argDefinition) {
-    if(argDefinition->value.variant.type != &UA_TYPES[UA_TYPES_ARGUMENT] &&
-        argDefinition->value.variant.type != &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])
+    if(argDefinition->value.variant.value.type != &UA_TYPES[UA_TYPES_ARGUMENT] &&
+        argDefinition->value.variant.value.type != &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])
         return UA_STATUSCODE_BADINTERNALERROR;
-    if(rs->inputArgumentsSize < argDefinition->value.variant.arrayLength) 
+    if(rs->inputArgumentsSize < argDefinition->value.variant.value.arrayLength)
         return UA_STATUSCODE_BADARGUMENTSMISSING;
-    if(rs->inputArgumentsSize > argDefinition->value.variant.arrayLength)
+    if(rs->inputArgumentsSize > argDefinition->value.variant.value.arrayLength)
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     
     const UA_ExtensionObject *thisArgDefExtObj;
@@ -89,16 +89,16 @@ static UA_StatusCode argConformsToDefinition(UA_CallMethodRequest *rs, const UA_
     UA_NodeId ArgumentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ARGUMENT + UA_ENCODINGOFFSET_BINARY);
     for(int i = 0; i<rs->inputArgumentsSize; i++) {
         var = &rs->inputArguments[i];
-        if(argDefinition->value.variant.type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) {
-            thisArgDefExtObj = &((const UA_ExtensionObject *) (argDefinition->value.variant.data))[i];
+        if(argDefinition->value.variant.value.type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) {
+            thisArgDefExtObj = &((const UA_ExtensionObject *) (argDefinition->value.variant.value.data))[i];
             decodingOffset = 0;
             
             if(!UA_NodeId_equal(&ArgumentNodeId, &thisArgDefExtObj->typeId))
                 return UA_STATUSCODE_BADINTERNALERROR;
                 
             UA_decodeBinary(&thisArgDefExtObj->body, &decodingOffset, &arg, &UA_TYPES[UA_TYPES_ARGUMENT]);
-        } else if(argDefinition->value.variant.type == &UA_TYPES[UA_TYPES_ARGUMENT])
-            arg = ((UA_Argument *) argDefinition->value.variant.data)[i];
+        } else if(argDefinition->value.variant.value.type == &UA_TYPES[UA_TYPES_ARGUMENT])
+            arg = ((UA_Argument *) argDefinition->value.variant.value.data)[i];
         retval |= statisfySignature(var, arg);
     }
     return retval;
@@ -178,8 +178,8 @@ static void callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequ
     // Call method if available
     if(methodCalled->attachedMethod) {
         result->outputArguments = UA_Array_new(&UA_TYPES[UA_TYPES_VARIANT],
-                                               outputArguments->value.variant.arrayLength);
-        result->outputArgumentsSize = outputArguments->value.variant.arrayLength;
+                                               outputArguments->value.variant.value.arrayLength);
+        result->outputArgumentsSize = outputArguments->value.variant.value.arrayLength;
         result->statusCode = methodCalled->attachedMethod(withObject->nodeId, request->inputArguments,
                                                           result->outputArguments, methodCalled->methodHandle);
     }

+ 1 - 1
src/server/ua_services_nodemanagement.c

@@ -90,7 +90,7 @@ static UA_StatusCode parseVariableNode(const UA_ExtensionObject *attributes, UA_
     /* } */
 
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
-        vnode->value.variant = attr.value;
+        vnode->value.variant.value = attr.value;
         UA_Variant_init(&attr.value);
     }
 

+ 6 - 3
src/server/ua_subscription.c

@@ -12,7 +12,7 @@ UA_Subscription *UA_Subscription_new(UA_Int32 subscriptionID) {
         return UA_NULL;
     new->subscriptionID = subscriptionID;
     new->lastPublished  = 0;
-    new->sequenceNumber = 0;
+    new->sequenceNumber = 1;
     memset(&new->timedUpdateJobGuid, 0, sizeof(UA_Guid));
     new->timedUpdateJob          = UA_NULL;
     new->timedUpdateIsRegistered = UA_FALSE;
@@ -113,7 +113,9 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
         // Decrement KeepAlive
         subscription->keepAliveCount.currentValue--;
         // +- Generate KeepAlive msg if counter overruns
-        Subscription_generateKeepAlive(subscription);
+        if (subscription->keepAliveCount.currentValue < subscription->keepAliveCount.minValue)
+          Subscription_generateKeepAlive(subscription);
+        
         return;
     }
     
@@ -426,7 +428,8 @@ UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, cons
         if(src->nodeClass == UA_NODECLASS_VARIABLE) {
             const UA_VariableNode *vsrc = (const UA_VariableNode*)src;
             if(srcAsVariableNode->valueSource == UA_VALUESOURCE_VARIANT) {
-                UA_Variant_copy(&vsrc->value.variant, dst);
+                UA_Variant_copy(&vsrc->value.variant.value, dst);
+                //no onRead callback here since triggered by a subscription
                 samplingError = UA_FALSE;
             } else {
                 if(srcAsVariableNode->valueSource != UA_VALUESOURCE_DATASOURCE)

+ 61 - 40
src/ua_connection.c

@@ -16,88 +16,109 @@ void UA_Connection_init(UA_Connection *connection) {
     connection->sockfd = 0;
     connection->handle = UA_NULL;
     UA_ByteString_init(&connection->incompleteMessage);
-    connection->write = UA_NULL;
+    connection->send = UA_NULL;
     connection->close = UA_NULL;
     connection->recv = UA_NULL;
-    connection->getBuffer = UA_NULL;
-    connection->releaseBuffer = UA_NULL;
+    connection->getSendBuffer = UA_NULL;
+    connection->releaseSendBuffer = UA_NULL;
+    connection->releaseRecvBuffer = UA_NULL;
 }
 
 void UA_Connection_deleteMembers(UA_Connection *connection) {
     UA_ByteString_deleteMembers(&connection->incompleteMessage);
 }
 
-UA_ByteString UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received)
-{
+UA_Job UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received) {
+    UA_Job job = (UA_Job){.type = UA_JOBTYPE_NOTHING};
     if(received.length == -1)
-        return received;
+        return job;
 
-    /* concat the existing incomplete message with the new message */
     UA_ByteString current;
-    if(connection->incompleteMessage.length < 0)
+    if(connection->incompleteMessage.length <= 0)
         current = received;
     else {
+        /* concat the existing incomplete message with the new message */
         current.data = UA_realloc(connection->incompleteMessage.data,
                                   connection->incompleteMessage.length + received.length);
         if(!current.data) {
             /* not enough memory */
             UA_ByteString_deleteMembers(&connection->incompleteMessage);
-            connection->incompleteMessage.length = -1;
-            UA_ByteString_deleteMembers(&received);
-            received.length = -1;
-            return received;
+            connection->releaseRecvBuffer(connection, &received);
+            return job;
         }
         UA_memcpy(current.data + connection->incompleteMessage.length, received.data, received.length);
         current.length = connection->incompleteMessage.length + received.length;
-        UA_ByteString_deleteMembers(&received);
+        connection->releaseRecvBuffer(connection, &received);
         UA_ByteString_init(&connection->incompleteMessage);
     }
 
-    /* find the first non-complete message */
-    size_t end_pos = 0; // the end of the last complete message
-    while(current.length - end_pos >= 16) {
-        if(!(current.data[0] == 'M' && current.data[1] == 'S' && current.data[2] == 'G') &&
-           !(current.data[0] == 'O' && current.data[1] == 'P' && current.data[2] == 'N') &&
-           !(current.data[0] == 'H' && current.data[1] == 'E' && current.data[2] == 'L') &&
-           !(current.data[0] == 'A' && current.data[1] == 'C' && current.data[2] == 'K') &&
-           !(current.data[0] == 'C' && current.data[1] == 'L' && current.data[2] == 'O')) {
-            current.length = end_pos; // throw the remaining bytestring away
+    /* the while loop sets pos to the first element after the last complete message. if a message
+       contains garbage, the buffer length is set to contain only the "good" messages before. */
+    size_t pos = 0;
+    while(current.length - pos >= 16) {
+        UA_UInt32 msgtype = current.data[pos] + (current.data[pos+1] << 8) + (current.data[pos+2] << 16);
+        if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
+           msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
+           msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
+           msgtype != ('A' + ('C' << 8) + ('K' << 16)) &&
+           msgtype != ('C' + ('L' << 8) + ('O' << 16))) {
+            /* the message type is not recognized. throw the remaining bytestring away */
+            current.length = pos;
             break;
         }
         UA_Int32 length = 0;
-        size_t pos = end_pos + 4;
-        UA_StatusCode retval = UA_Int32_decodeBinary(&current, &pos, &length);
+        size_t length_pos = pos + 4;
+        UA_StatusCode retval = UA_Int32_decodeBinary(&current, &length_pos, &length);
         if(retval != UA_STATUSCODE_GOOD || length < 16 ||
            length > (UA_Int32)connection->localConf.maxMessageSize) {
-            current.length = end_pos; // throw the remaining bytestring away
+            /* the message size is not allowed. throw the remaining bytestring away */
+            current.length = pos;
             break;
         }
-        if(length + (UA_Int32)end_pos > current.length)
-            break; // the message is incomplete
-        end_pos += length;
+        if(length + (UA_Int32)pos > current.length)
+            break; /* the message is incomplete. keep the beginning */
+        pos += length;
     }
 
     if(current.length == 0) {
         /* throw everything away */
-        UA_ByteString_deleteMembers(&current);
-        current.length = -1;
-        return current;
+        if(current.data == received.data)
+            connection->releaseRecvBuffer(connection, &received);
+        else
+            UA_ByteString_deleteMembers(&current);
+        return job;
     }
 
-    if(end_pos == 0) {
+    if(pos == 0) {
         /* no complete message in current */
-        connection->incompleteMessage = current;
-        UA_ByteString_init(&current);
-    } else if(current.length != (UA_Int32)end_pos) {
+        if(current.data == received.data) {
+            /* copy the data into the connection */
+            UA_ByteString_copy(&current, &connection->incompleteMessage);
+            connection->releaseRecvBuffer(connection, &received);
+        } else {
+            /* the data is already copied off the network stack */
+            connection->incompleteMessage = current;
+        }
+        return job;
+    }
+
+    if(current.length != (UA_Int32)pos) {
         /* there is an incomplete message at the end of current */
-        connection->incompleteMessage.data = UA_malloc(current.length - end_pos);
+        connection->incompleteMessage.data = UA_malloc(current.length - pos);
         if(connection->incompleteMessage.data) {
-            UA_memcpy(connection->incompleteMessage.data, &current.data[end_pos], current.length - end_pos);
-            connection->incompleteMessage.length = current.length - end_pos;
+            UA_memcpy(connection->incompleteMessage.data, &current.data[pos], current.length - pos);
+            connection->incompleteMessage.length = current.length - pos;
         }
-        current.length = end_pos;
+        current.length = pos;
     }
-    return current;
+
+    job.job.binaryMessage.message = current;
+    job.job.binaryMessage.connection = connection;
+    if(current.data == received.data)
+        job.type = UA_JOBTYPE_BINARYMESSAGE_NETWORKLAYER;
+    else
+        job.type = UA_JOBTYPE_BINARYMESSAGE_ALLOCATED;
+    return job;
 }
 
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {

+ 6 - 6
src/ua_securechannel.c

@@ -124,7 +124,8 @@ UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_U
     seqHeader.requestId = requestId;
 
     UA_ByteString message;
-    UA_StatusCode retval = connection->getBuffer(connection, &message);
+    UA_StatusCode retval = connection->getSendBuffer(connection, connection->remoteConf.recvBufferSize,
+                                                     &message);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
@@ -133,7 +134,7 @@ UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_U
     retval |= UA_encodeBinary(content, contentType, &message, &messagePos);
 
     if(retval != UA_STATUSCODE_GOOD) {
-        connection->releaseBuffer(connection, &message);
+        connection->releaseSendBuffer(connection, &message);
         return retval;
     }
 
@@ -149,9 +150,8 @@ UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_U
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &message, &messagePos);
     UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, &message, &messagePos);
     UA_SequenceHeader_encodeBinary(&seqHeader, &message, &messagePos);
-    
-    retval = connection->write(connection, &message, respHeader.messageHeader.messageSize);
-    if(retval != UA_STATUSCODE_GOOD)
-        connection->releaseBuffer(connection, &message);
+    message.length = respHeader.messageHeader.messageSize;
+
+    retval = connection->send(connection, &message);
     return retval;
 }

+ 1 - 0
src/ua_types.c

@@ -97,6 +97,7 @@ void UA_String_init(UA_String *p) {
 void UA_String_deleteMembers(UA_String *p) {
     UA_free(p->data);
     p->data = UA_NULL;
+    p->length = -1;
 }
 
 UA_StatusCode UA_String_copy(UA_String const *src, UA_String *dst) {

+ 1 - 1
tests/check_services_attributes.c

@@ -82,7 +82,7 @@ static UA_VariableNode* makeCompareSequence(void) {
     const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
 	UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
 	//UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-	node->value.variant=*myIntegerVariant;
+	node->value.variant.value = *myIntegerVariant;
 	UA_NodeId_copy(&myIntegerNodeId,&node->nodeId);
 	UA_QualifiedName_copy(&myIntegerName,&node->browseName);
     UA_LocalizedText_copy(&myIntegerDisplName, &node->displayName);

+ 3 - 3
tools/pyUANamespace/ua_builtin_types.py

@@ -367,7 +367,7 @@ class opcua_value_t():
         code.append("UA_Variant_setArrayCopy(" + self.parent.getCodePrintableID() + "_variant, &" + valueName + ", (UA_Int32) " + str(len(self.value)) + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
         # Variant creation is now part of printSubtypeEarly, the node does not exist when the type is initialized!
         #if (bootstrapping == True):
-        #  code.append(self.parent.getCodePrintableID() + "->value.variant = *" + self.parent.getCodePrintableID() + "_variant;")
+        #  code.append(self.parent.getCodePrintableID() + "->value.variant.value = *" + self.parent.getCodePrintableID() + "_variant;")
     else:
       # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
       if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_GUID:
@@ -391,14 +391,14 @@ class opcua_value_t():
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
           # Variant creation is now part of printSubtypeEarly, the node does not exist when the type is initialized!
           #if (bootstrapping == True):
-          #  code.append(self.parent.getCodePrintableID() + "->value.variant = *" + self.parent.getCodePrintableID() + "_variant;")
+          #  code.append(self.parent.getCodePrintableID() + "->value.variant.value = *" + self.parent.getCodePrintableID() + "_variant;")
         else:
           code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
           code.append("UA_Variant_setScalarCopy(" + self.parent.getCodePrintableID() + "_variant, &" + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(&" + valueName + ");")
           # Variant creation is now part of printSubtypeEarly, the node does not exist when the type is initialized!
           #if (bootstrapping == True):
-          #  code.append(self.parent.getCodePrintableID() + "->value.variant = *" + self.parent.getCodePrintableID() + "_variant;")
+          #  code.append(self.parent.getCodePrintableID() + "->value.variant.value = *" + self.parent.getCodePrintableID() + "_variant;")
     return code
 
 

+ 2 - 2
tools/pyUANamespace/ua_node_types.py

@@ -1096,7 +1096,7 @@ class opcua_node_variable_t(opcua_node_t):
     code.append(self.getCodePrintableID() + "->accessLevel = (UA_Int32) " + str(self.accessLevel()) + ";")
     code.append(self.getCodePrintableID() + "->valueRank = (UA_Int32) " + str(self.valueRank()) + ";")
     # The variant is guaranteed to exist by SubtypeEarly()
-    code.append(self.getCodePrintableID() + "->value.variant = *" + self.getCodePrintableID() + "_variant;")
+    code.append(self.getCodePrintableID() + "->value.variant.value = *" + self.getCodePrintableID() + "_variant;")
     return code
 
 class opcua_node_method_t(opcua_node_t):
@@ -1348,7 +1348,7 @@ class opcua_node_variableType_t(opcua_node_t):
       code.append(self.getCodePrintableID() + "->isAbstract = UA_FALSE;")
     
     # The variant is guaranteed to exist by SubtypeEarly()
-    code.append(self.getCodePrintableID() + "->value.variant = *" + self.getCodePrintableID() + "_variant;")
+    code.append(self.getCodePrintableID() + "->value.variant.value = *" + self.getCodePrintableID() + "_variant;")
     return code
 
 class opcua_node_dataType_t(opcua_node_t):