Browse Source

Merge remote-tracking branch 'master' into feature/addmethodnodeex

Thomas Bender 7 years ago
parent
commit
de16606199
50 changed files with 460 additions and 165 deletions
  1. 7 0
      .clang-format
  2. 27 0
      .editorconfig
  3. 3 0
      .travis.yml
  4. 13 0
      CHANGELOG
  5. 16 4
      CMakeLists.txt
  6. 16 0
      CPPLINT.cfg
  7. 0 1
      doc/building.rst
  8. 1 1
      examples/client.c
  9. 1 1
      examples/client_subscription_loop.c
  10. 2 1
      examples/tutorial_client_events.c
  11. 4 3
      include/ua_client_highlevel.h
  12. 2 0
      include/ua_plugin_securitypolicy.h
  13. 2 2
      plugins/ua_config_default.c
  14. 0 4
      plugins/ua_network_udp.c
  15. 1 0
      plugins/ua_pki_certificate.c
  16. 20 17
      plugins/ua_securitypolicy_basic128rsa15.c
  17. 1 0
      plugins/ua_securitypolicy_basic128rsa15.h
  18. 4 2
      plugins/ua_securitypolicy_none.c
  19. 2 2
      plugins/ua_securitypolicy_none.h
  20. 2 2
      src/client/ua_client.c
  21. 1 1
      src/client/ua_client_connect.c
  22. 3 2
      src/client/ua_client_highlevel_subscriptions.c
  23. 3 0
      src/client/ua_client_internal.h
  24. 2 2
      src/server/ua_mdns.c
  25. 2 2
      src/server/ua_securechannel_manager.c
  26. 3 2
      src/server/ua_server.c
  27. 11 8
      src/server/ua_server_internal.h
  28. 34 29
      src/server/ua_server_worker.c
  29. 23 16
      src/server/ua_services_attribute.c
  30. 3 3
      src/server/ua_services_discovery.c
  31. 1 1
      src/server/ua_services_nodemanagement.c
  32. 22 3
      src/server/ua_session.c
  33. 2 2
      src/server/ua_session_manager.c
  34. 36 25
      src/ua_securechannel.c
  35. 8 0
      src/ua_types_encoding_binary.c
  36. 43 1
      src/ua_util.h
  37. 34 0
      tests/client/check_client.c
  38. 1 1
      tests/client/check_client_subscriptions.c
  39. 1 1
      tests/fuzz/corpus_generator.c
  40. 5 3
      tests/testing-plugins/testing_policy.c
  41. 1 1
      tools/amalgamate.py
  42. 56 0
      tools/clang-format_precommit_hook
  43. 15 4
      tools/generate_datatypes.py
  44. 3 3
      tools/generate_statuscode_descriptions.py
  45. 3 4
      tools/nodeset_compiler/backend_open62541.py
  46. 3 3
      tools/nodeset_compiler/backend_open62541_datatypes.py
  47. 6 6
      tools/nodeset_compiler/backend_open62541_nodes.py
  48. 1 1
      tools/travis/travis_linux_before_install.sh
  49. 10 0
      tools/travis/travis_linux_script.sh
  50. 0 1
      tools/travis/travis_osx_before_install.sh

+ 7 - 0
.clang-format

@@ -0,0 +1,7 @@
+---
+Language:        Cpp
+BasedOnStyle:    llvm
+ColumnLimit:     120
+ForEachMacros:   [ foreach, LIST_FOREACH, LIST_FOREACH_SAFE ]
+DisableFormat:   false
+

+ 27 - 0
.editorconfig

@@ -0,0 +1,27 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+
+# Matches multiple files with brace expansion notation
+# Set default charset
+[*.{js,py}]
+charset = utf-8
+
+# Tab indentation (no size specified)
+[Makefile]
+indent_style = tab
+
+# Matches the exact files either package.json or .travis.yml
+[{package.json,.travis.yml,appveyor.yml}]
+indent_style = space
+indent_size = 2
+
+

+ 3 - 0
.travis.yml

@@ -50,6 +50,9 @@ matrix:
     - os: linux
     - os: linux
       compiler: clang
       compiler: clang
       env: FUZZER=true
       env: FUZZER=true
+    #- os: linux
+    #  compiler: gcc
+    #  env: LINT=true
     # - os: osx
     # - os: osx
     #   compiler: clang
     #   compiler: clang
     #   # disable homebrew auto update which takes a lot of time
     #   # disable homebrew auto update which takes a lot of time

+ 13 - 0
CHANGELOG

@@ -1,6 +1,19 @@
 This changelog reports changes to the public API. Internal refactorings and bug
 This changelog reports changes to the public API. Internal refactorings and bug
 fixes are not reported here.
 fixes are not reported here.
 
 
+2018-02-05 pro <profanter at fortiss.org>
+
+ * Also pass client to monitoredItem/Events callback
+
+   The UA_MonitoredItemHandlingFunction and UA_MonitoredEventHandlingFunction
+   did not include a reference to the corresponding client used for the call of
+   processPublishResponse.
+   This now also allows to get the client context within the monitored item
+   handling function.
+
+   The API changes are detected by the type-matching in the compiler. So there
+   is little risk for bugs due to unaligned implementations.
+
 2017-09-07 jpfr <julius.pfrommer at web.de>
 2017-09-07 jpfr <julius.pfrommer at web.de>
 
 
  * Make Client Highlevel Interface consistent
  * Make Client Highlevel Interface consistent

+ 16 - 4
CMakeLists.txt

@@ -188,7 +188,10 @@ if(NOT WIN32)
     list(APPEND open62541_LIBRARIES c)
     list(APPEND open62541_LIBRARIES c)
     list(APPEND open62541_LIBRARIES stdc++)
     list(APPEND open62541_LIBRARIES stdc++)
   else()
   else()
-    list(APPEND open62541_LIBRARIES pthread m)
+    list(APPEND open62541_LIBRARIES m)
+    if(UA_ENABLE_MULTITHREADING OR UA_BUILD_UNIT_TESTS)
+      list(APPEND open62541_LIBRARIES pthread)
+    endif()
     if(NOT APPLE AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
     if(NOT APPLE AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
       list(APPEND open62541_LIBRARIES rt)
       list(APPEND open62541_LIBRARIES rt)
     endif()
     endif()
@@ -199,9 +202,6 @@ else()
         list(APPEND open62541_LIBRARIES iphlpapi)
         list(APPEND open62541_LIBRARIES iphlpapi)
     endif()
     endif()
 endif()
 endif()
-if(UA_ENABLE_MULTITHREADING)
-  list(APPEND open62541_LIBRARIES urcu-cds urcu-bp urcu-common)
-endif(UA_ENABLE_MULTITHREADING)
 
 
 #####################
 #####################
 # Compiler Settings #
 # Compiler Settings #
@@ -717,6 +717,18 @@ add_custom_target(lint ${CLANG_TIDY_PROGRAM}
                   COMMENT "Run clang-tidy on the library")
                   COMMENT "Run clang-tidy on the library")
 add_dependencies(lint open62541)
 add_dependencies(lint open62541)
 
 
+add_custom_target(cpplint cpplint
+                  ${lib_sources}
+                  ${internal_headers}
+                  ${default_plugin_headers}
+                  ${default_plugin_sources}
+                  DEPENDS ${lib_sources}
+                          ${internal_headers}
+                          ${default_plugin_headers}
+                          ${default_plugin_sources}
+
+                  COMMENT "Run cpplint code style checker on the library")
+
 ##########################
 ##########################
 # Installation           #
 # Installation           #
 ##########################
 ##########################

+ 16 - 0
CPPLINT.cfg

@@ -0,0 +1,16 @@
+set noparent
+filter=-whitespace/line_length
+filter=-readability/casting
+filter=-legal/copyright
+filter=-build/include_subdir
+filter=-readability/todo
+filter=-runtime/casting
+filter=-runtime/int
+filter=-build/include_what_you_use
+filter=-readability/multiline_comment
+filter=-runtime/printf
+filter=-build/include
+filter=-build/header_guard
+filter=-readability/alt_tokens
+filter=-runtime/indentation_namespace
+exclude_files=deps/*

+ 0 - 1
doc/building.rst

@@ -27,7 +27,6 @@ Building with CMake on Ubuntu or Debian
    # enable additional features
    # enable additional features
    sudo apt-get install cmake-curses-gui # for the ccmake graphical interface
    sudo apt-get install cmake-curses-gui # for the ccmake graphical interface
    sudo apt-get install libmbedtls-dev # for encryption support
    sudo apt-get install libmbedtls-dev # for encryption support
-   sudo apt-get install liburcu-dev # for multithreading
    sudo apt-get install check # for unit tests
    sudo apt-get install check # for unit tests
    sudo apt-get install python-sphinx graphviz # for documentation generation
    sudo apt-get install python-sphinx graphviz # for documentation generation
    sudo apt-get install python-sphinx-rtd-theme # documentation style
    sudo apt-get install python-sphinx-rtd-theme # documentation style

+ 1 - 1
examples/client.c

@@ -6,7 +6,7 @@
 
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 static void
 static void
-handler_TheAnswerChanged(UA_UInt32 monId, UA_DataValue *value, void *context) {
+handler_TheAnswerChanged(UA_Client *client, UA_UInt32 monId, UA_DataValue *value, void *context) {
     printf("The Answer has changed!\n");
     printf("The Answer has changed!\n");
 }
 }
 #endif
 #endif

+ 1 - 1
examples/client_subscription_loop.c

@@ -43,7 +43,7 @@ static void stopHandler(int sign) {
 }
 }
 
 
 static void
 static void
-handler_currentTimeChanged(UA_UInt32 monId, UA_DataValue *value, void *context) {
+handler_currentTimeChanged(UA_Client *client, UA_UInt32 monId, UA_DataValue *value, void *context) {
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "currentTime has changed!");
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "currentTime has changed!");
     if(UA_Variant_hasScalarType(&value->value, &UA_TYPES[UA_TYPES_DATETIME])) {
     if(UA_Variant_hasScalarType(&value->value, &UA_TYPES[UA_TYPES_DATETIME])) {
         UA_DateTime raw_date = *(UA_DateTime *) value->value.data;
         UA_DateTime raw_date = *(UA_DateTime *) value->value.data;

+ 2 - 1
examples/tutorial_client_events.c

@@ -14,7 +14,8 @@ static void stopHandler(int sig) {
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 
 
 static void
 static void
-handler_events(const UA_UInt32 monId, const size_t nEventFields,
+handler_events(UA_Client *client,
+               const UA_UInt32 monId, const size_t nEventFields,
                const UA_Variant *eventFields, void *context) {
                const UA_Variant *eventFields, void *context) {
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Notification");
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Notification");
 
 

+ 4 - 3
include/ua_client_highlevel.h

@@ -597,8 +597,8 @@ UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client);
 
 
 /* Addition of monitored DataChanges */
 /* Addition of monitored DataChanges */
 /* TODO for v0.4: Rename method to _DataChange. */
 /* TODO for v0.4: Rename method to _DataChange. */
-typedef void (*UA_MonitoredItemHandlingFunction)(UA_UInt32 monId, UA_DataValue *value,
-                                                 void *context);
+typedef void (*UA_MonitoredItemHandlingFunction)(UA_Client *client, UA_UInt32 monId,
+                                                 UA_DataValue *value, void *context);
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Client_Subscriptions_addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId,
 UA_Client_Subscriptions_addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId,
@@ -617,7 +617,8 @@ UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscripti
 
 
 /* Monitored Events have different payloads from DataChanges. So they use a
 /* Monitored Events have different payloads from DataChanges. So they use a
  * different callback method signature. */
  * different callback method signature. */
-typedef void (*UA_MonitoredEventHandlingFunction)(const UA_UInt32 monId,
+typedef void (*UA_MonitoredEventHandlingFunction)(UA_Client *client,
+                                                  const UA_UInt32 monId,
                                                   const size_t nEventFields,
                                                   const size_t nEventFields,
                                                   const UA_Variant *eventFields,
                                                   const UA_Variant *eventFields,
                                                   void *context);
                                                   void *context);

+ 2 - 0
include/ua_plugin_securitypolicy.h

@@ -17,6 +17,7 @@ extern "C" {
 #include "ua_types.h"
 #include "ua_types.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 #include "ua_plugin_log.h"
 #include "ua_plugin_log.h"
+#include "ua_plugin_pki.h"
 
 
 extern const UA_ByteString UA_SECURITY_POLICY_NONE_URI;
 extern const UA_ByteString UA_SECURITY_POLICY_NONE_URI;
 
 
@@ -295,6 +296,7 @@ struct UA_SecurityPolicy {
     UA_SecurityPolicyAsymmetricModule asymmetricModule;
     UA_SecurityPolicyAsymmetricModule asymmetricModule;
     UA_SecurityPolicySymmetricModule symmetricModule;
     UA_SecurityPolicySymmetricModule symmetricModule;
     UA_SecurityPolicyChannelModule channelModule;
     UA_SecurityPolicyChannelModule channelModule;
+    UA_CertificateVerification *certificateVerification;
 
 
     UA_Logger logger;
     UA_Logger logger;
 
 

+ 2 - 2
plugins/ua_config_default.c

@@ -75,7 +75,7 @@ createSecurityPolicyNoneEndpoint(UA_ServerConfig *conf, UA_Endpoint *endpoint,
                                  const UA_ByteString localCertificate) {
                                  const UA_ByteString localCertificate) {
     UA_EndpointDescription_init(&endpoint->endpointDescription);
     UA_EndpointDescription_init(&endpoint->endpointDescription);
 
 
-    UA_SecurityPolicy_None(&endpoint->securityPolicy, localCertificate, conf->logger);
+    UA_SecurityPolicy_None(&endpoint->securityPolicy, NULL, localCertificate, conf->logger);
     endpoint->endpointDescription.securityMode = UA_MESSAGESECURITYMODE_NONE;
     endpoint->endpointDescription.securityMode = UA_MESSAGESECURITYMODE_NONE;
     endpoint->endpointDescription.securityPolicyUri =
     endpoint->endpointDescription.securityPolicyUri =
         UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
         UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
@@ -127,7 +127,7 @@ createSecurityPolicyBasic128Rsa15Endpoint(UA_ServerConfig *const conf,
     UA_EndpointDescription_init(&endpoint->endpointDescription);
     UA_EndpointDescription_init(&endpoint->endpointDescription);
 
 
     UA_StatusCode retval =
     UA_StatusCode retval =
-        UA_SecurityPolicy_Basic128Rsa15(&endpoint->securityPolicy, localCertificate,
+        UA_SecurityPolicy_Basic128Rsa15(&endpoint->securityPolicy, &conf->certificateVerification, localCertificate,
                                         localPrivateKey, conf->logger);
                                         localPrivateKey, conf->logger);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         endpoint->securityPolicy.deleteMembers(&endpoint->securityPolicy);
         endpoint->securityPolicy.deleteMembers(&endpoint->securityPolicy);

+ 0 - 4
plugins/ua_network_udp.c

@@ -9,10 +9,6 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h> // memset
 #include <string.h> // memset
 
 
-#ifdef UA_ENABLE_MULTITHREADING
-# include <urcu/uatomic.h>
-#endif
-
 /* with a space so amalgamation does not remove the includes */
 /* with a space so amalgamation does not remove the includes */
 # include <errno.h> // errno, EINTR
 # include <errno.h> // errno, EINTR
 # include <fcntl.h> // fcntl
 # include <fcntl.h> // fcntl

+ 1 - 0
plugins/ua_pki_certificate.c

@@ -46,6 +46,7 @@ certificateVerification_verify(void *verificationContext,
 
 
     /* Parse the certificate */
     /* Parse the certificate */
     mbedtls_x509_crt remoteCertificate;
     mbedtls_x509_crt remoteCertificate;
+    mbedtls_x509_crt_init(&remoteCertificate);
     int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
     int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
                                          certificate->length);
                                          certificate->length);
     if(mbedErr) {
     if(mbedErr) {

+ 20 - 17
plugins/ua_securitypolicy_basic128rsa15.c

@@ -13,6 +13,7 @@
 #include <mbedtls/entropy.h>
 #include <mbedtls/entropy.h>
 #include <mbedtls/entropy_poll.h>
 #include <mbedtls/entropy_poll.h>
 #include <mbedtls/error.h>
 #include <mbedtls/error.h>
+#include <ua_plugin_pki.h>
 
 
 #include "ua_securitypolicy_basic128rsa15.h"
 #include "ua_securitypolicy_basic128rsa15.h"
 #include "ua_types.h"
 #include "ua_types.h"
@@ -271,7 +272,7 @@ asymmetricModule_compareCertificateThumbprint_sp_basic128rsa15(const UA_Security
     if(securityPolicy == NULL || certificateThumbprint == NULL)
     if(securityPolicy == NULL || certificateThumbprint == NULL)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
 
 
-    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext*)securityPolicy->policyContext;
+    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
     if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
     if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
         return UA_STATUSCODE_BADCERTIFICATEINVALID;
         return UA_STATUSCODE_BADCERTIFICATEINVALID;
 
 
@@ -306,7 +307,7 @@ sym_verify_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
     }
     }
 
 
     Basic128Rsa15_PolicyContext *pc =
     Basic128Rsa15_PolicyContext *pc =
-        (Basic128Rsa15_PolicyContext*)securityPolicy->policyContext;
+        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
 
 
     unsigned char mac[UA_SHA1_LENGTH];
     unsigned char mac[UA_SHA1_LENGTH];
     md_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey, message, mac);
     md_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey, message, mac);
@@ -355,7 +356,7 @@ sym_encrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
     if(data->length % cc->localSymEncryptingKey.length != 0) {
     if(data->length % cc->localSymEncryptingKey.length != 0) {
         UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
         UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                      "Length of data to encrypt is not a multiple of the encryptingKey length."
                      "Length of data to encrypt is not a multiple of the encryptingKey length."
-                     "Padding might not have been calculated appropriatley.");
+                         "Padding might not have been calculated appropriatley.");
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
 
 
@@ -393,7 +394,7 @@ sym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
 
 
-    unsigned int keylength = (unsigned int) (cc->remoteSymEncryptingKey.length * 8);
+    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
     mbedtls_aes_context aesContext;
     mbedtls_aes_context aesContext;
     int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
     int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
     UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADINTERNALERROR);
     UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADINTERNALERROR);
@@ -425,7 +426,7 @@ sym_generateKey_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
 
 
     Basic128Rsa15_PolicyContext *pc =
     Basic128Rsa15_PolicyContext *pc =
-        (Basic128Rsa15_PolicyContext*)securityPolicy->policyContext;
+        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
 
 
     size_t hashLen = 0;
     size_t hashLen = 0;
     const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
     const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
@@ -503,7 +504,7 @@ sym_generateNonce_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
 
 
     Basic128Rsa15_PolicyContext *data =
     Basic128Rsa15_PolicyContext *data =
-        (Basic128Rsa15_PolicyContext *) securityPolicy->policyContext;
+        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
 
 
     int mbedErr = mbedtls_ctr_drbg_random(&data->drbgContext, out->data, out->length);
     int mbedErr = mbedtls_ctr_drbg_random(&data->drbgContext, out->data, out->length);
     UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADUNEXPECTEDERROR);
     UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADUNEXPECTEDERROR);
@@ -526,7 +527,7 @@ parseRemoteCertificate_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
 
 
     /* Parse the certificate */
     /* Parse the certificate */
     int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
     int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
-                                          remoteCertificate->length);
+                                         remoteCertificate->length);
     UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADSECURITYCHECKSFAILED);
     UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADSECURITYCHECKSFAILED);
 
 
     /* Check the key length */
     /* Check the key length */
@@ -565,10 +566,10 @@ channelContext_newContext_sp_basic128rsa15(const UA_SecurityPolicy *securityPoli
     if(*pp_contextData == NULL)
     if(*pp_contextData == NULL)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
 
-    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext*)*pp_contextData;
+    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)*pp_contextData;
 
 
     /* Initialize the channel context */
     /* Initialize the channel context */
-    cc->policyContext = (Basic128Rsa15_PolicyContext*)securityPolicy->policyContext;
+    cc->policyContext = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
 
 
     UA_ByteString_init(&cc->localSymSigningKey);
     UA_ByteString_init(&cc->localSymSigningKey);
     UA_ByteString_init(&cc->localSymEncryptingKey);
     UA_ByteString_init(&cc->localSymEncryptingKey);
@@ -681,7 +682,7 @@ static size_t
 channelContext_getRemoteAsymEncryptionBufferLengthOverhead_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc,
 channelContext_getRemoteAsymEncryptionBufferLengthOverhead_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc,
                                                                             size_t maxEncryptionLength) {
                                                                             size_t maxEncryptionLength) {
     const size_t maxNumberOfBlocks = maxEncryptionLength /
     const size_t maxNumberOfBlocks = maxEncryptionLength /
-        channelContext_getRemoteAsymPlainTextBlockSize_sp_basic128rsa15(cc);
+                                     channelContext_getRemoteAsymPlainTextBlockSize_sp_basic128rsa15(cc);
     return maxNumberOfBlocks * UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
     return maxNumberOfBlocks * UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
 }
 }
 
 
@@ -696,7 +697,7 @@ deleteMembers_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy) {
     UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
     UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
 
 
     /* delete all allocated members in the context */
     /* delete all allocated members in the context */
-    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext*)
+    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
         securityPolicy->policyContext;
         securityPolicy->policyContext;
 
 
     mbedtls_ctr_drbg_free(&pc->drbgContext);
     mbedtls_ctr_drbg_free(&pc->drbgContext);
@@ -721,7 +722,7 @@ policyContext_newContext_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
 
 
     Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
     Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
         UA_malloc(sizeof(Basic128Rsa15_PolicyContext));
         UA_malloc(sizeof(Basic128Rsa15_PolicyContext));
-    securityPolicy->policyContext = (void*)pc;
+    securityPolicy->policyContext = (void *)pc;
     if(!pc) {
     if(!pc) {
         retval = UA_STATUSCODE_BADOUTOFMEMORY;
         retval = UA_STATUSCODE_BADOUTOFMEMORY;
         goto error;
         goto error;
@@ -788,8 +789,9 @@ error:
 }
 }
 
 
 UA_StatusCode
 UA_StatusCode
-UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
-                                const UA_ByteString localPrivateKey, UA_Logger logger) {
+UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, UA_CertificateVerification *certificateVerification,
+                                const UA_ByteString localCertificate, const UA_ByteString localPrivateKey,
+                                UA_Logger logger) {
     memset(policy, 0, sizeof(UA_SecurityPolicy));
     memset(policy, 0, sizeof(UA_SecurityPolicy));
     policy->logger = logger;
     policy->logger = logger;
 
 
@@ -801,12 +803,13 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString l
 
 
     /* Copy the certificate and add a NULL to the end */
     /* Copy the certificate and add a NULL to the end */
     UA_StatusCode retval =
     UA_StatusCode retval =
-        UA_ByteString_allocBuffer(&policy->localCertificate, localCertificate.length+1);
+        UA_ByteString_allocBuffer(&policy->localCertificate, localCertificate.length + 1);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
     memcpy(policy->localCertificate.data, localCertificate.data, localCertificate.length);
     memcpy(policy->localCertificate.data, localCertificate.data, localCertificate.length);
     policy->localCertificate.data[localCertificate.length] = '\0';
     policy->localCertificate.data[localCertificate.length] = '\0';
     policy->localCertificate.length--;
     policy->localCertificate.length--;
+    policy->certificateVerification = certificateVerification;
 
 
     /* AsymmetricModule */
     /* AsymmetricModule */
     asymmetricModule->cryptoModule.signatureAlgorithmUri =
     asymmetricModule->cryptoModule.signatureAlgorithmUri =
@@ -827,7 +830,7 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString l
         (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic128rsa15;
         (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))asym_encrypt_sp_basic128rsa15;
     asymmetricModule->cryptoModule.decrypt =
     asymmetricModule->cryptoModule.decrypt =
         (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))
         (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))
-        asym_decrypt_sp_basic128rsa15;
+            asym_decrypt_sp_basic128rsa15;
     asymmetricModule->cryptoModule.getLocalEncryptionKeyLength = NULL; // TODO: Write function
     asymmetricModule->cryptoModule.getLocalEncryptionKeyLength = NULL; // TODO: Write function
     asymmetricModule->cryptoModule.getRemoteEncryptionKeyLength =
     asymmetricModule->cryptoModule.getRemoteEncryptionKeyLength =
         (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteEncryptionKeyLength;
         (size_t (*)(const UA_SecurityPolicy *, const void *))asym_getRemoteEncryptionKeyLength;
@@ -858,7 +861,7 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString l
         (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_encrypt_sp_basic128rsa15;
         (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))sym_encrypt_sp_basic128rsa15;
     symmetricModule->cryptoModule.decrypt =
     symmetricModule->cryptoModule.decrypt =
         (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))
         (UA_StatusCode(*)(const UA_SecurityPolicy *, void *, UA_ByteString *))
-        sym_decrypt_sp_basic128rsa15;
+            sym_decrypt_sp_basic128rsa15;
     symmetricModule->cryptoModule.getLocalEncryptionKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15;
     symmetricModule->cryptoModule.getLocalEncryptionKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15;
     symmetricModule->cryptoModule.getRemoteEncryptionKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15;
     symmetricModule->cryptoModule.getRemoteEncryptionKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15;
 
 

+ 1 - 0
plugins/ua_securitypolicy_basic128rsa15.h

@@ -17,6 +17,7 @@ extern "C" {
 
 
 UA_EXPORT UA_StatusCode
 UA_EXPORT UA_StatusCode
 UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy,
 UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy,
+                                UA_CertificateVerification *certificateVerification,
                                 const UA_ByteString localCertificate,
                                 const UA_ByteString localCertificate,
                                 const UA_ByteString localPrivateKey,
                                 const UA_ByteString localPrivateKey,
                                 UA_Logger logger);
                                 UA_Logger logger);

+ 4 - 2
plugins/ua_securitypolicy_none.c

@@ -121,13 +121,15 @@ policy_deletemembers_none(UA_SecurityPolicy *policy) {
 }
 }
 
 
 UA_StatusCode
 UA_StatusCode
-UA_SecurityPolicy_None(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
-                       UA_Logger logger) {
+UA_SecurityPolicy_None(UA_SecurityPolicy *policy, UA_CertificateVerification *certificateVerification,
+                       const UA_ByteString localCertificate, UA_Logger logger) {
     policy->policyContext = (void *) (uintptr_t) logger;
     policy->policyContext = (void *) (uintptr_t) logger;
     policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
     policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
     policy->logger = logger;
     policy->logger = logger;
     UA_ByteString_copy(&localCertificate, &policy->localCertificate);
     UA_ByteString_copy(&localCertificate, &policy->localCertificate);
 
 
+    policy->certificateVerification = certificateVerification;
+
     policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_none;
     policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_none;
     policy->asymmetricModule.compareCertificateThumbprint = compareThumbprint_none;
     policy->asymmetricModule.compareCertificateThumbprint = compareThumbprint_none;
     policy->asymmetricModule.cryptoModule.signatureAlgorithmUri = UA_STRING_NULL;
     policy->asymmetricModule.cryptoModule.signatureAlgorithmUri = UA_STRING_NULL;

+ 2 - 2
plugins/ua_securitypolicy_none.h

@@ -16,8 +16,8 @@ extern "C" {
 #include "ua_plugin_log.h"
 #include "ua_plugin_log.h"
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_SecurityPolicy_None(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
-                       UA_Logger logger);
+UA_SecurityPolicy_None(UA_SecurityPolicy *policy, UA_CertificateVerification *certificateVerification,
+                       const UA_ByteString localCertificate, UA_Logger logger);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 2 - 2
src/client/ua_client.c

@@ -32,7 +32,7 @@ static void
 UA_Client_init(UA_Client* client, UA_ClientConfig config) {
 UA_Client_init(UA_Client* client, UA_ClientConfig config) {
     memset(client, 0, sizeof(UA_Client));
     memset(client, 0, sizeof(UA_Client));
     /* TODO: Select policy according to the endpoint */
     /* TODO: Select policy according to the endpoint */
-    UA_SecurityPolicy_None(&client->securityPolicy, UA_BYTESTRING_NULL, config.logger);
+    UA_SecurityPolicy_None(&client->securityPolicy, NULL, UA_BYTESTRING_NULL, config.logger);
     client->channel.securityPolicy = &client->securityPolicy;
     client->channel.securityPolicy = &client->securityPolicy;
     client->channel.securityMode = UA_MESSAGESECURITYMODE_NONE;
     client->channel.securityMode = UA_MESSAGESECURITYMODE_NONE;
     client->config = config;
     client->config = config;
@@ -306,7 +306,7 @@ receiveServiceResponse(UA_Client *client, void *response, const UA_DataType *res
 
 
         if(retval != UA_STATUSCODE_GOOD && retval != UA_STATUSCODE_GOODNONCRITICALTIMEOUT) {
         if(retval != UA_STATUSCODE_GOOD && retval != UA_STATUSCODE_GOODNONCRITICALTIMEOUT) {
             if(retval == UA_STATUSCODE_BADCONNECTIONCLOSED)
             if(retval == UA_STATUSCODE_BADCONNECTIONCLOSED)
-                client->state = UA_CLIENTSTATE_DISCONNECTED;
+                setClientState(client, UA_CLIENTSTATE_DISCONNECTED);
             UA_Client_close(client);
             UA_Client_close(client);
             break;
             break;
         }
         }

+ 1 - 1
src/client/ua_client_connect.c

@@ -22,7 +22,7 @@
  /********************/
  /********************/
  /* Set client state */
  /* Set client state */
  /********************/
  /********************/
-static void
+void
 setClientState(UA_Client *client, UA_ClientState state)
 setClientState(UA_Client *client, UA_ClientState state)
 {
 {
     if(client->state != state) {
     if(client->state != state) {

+ 3 - 2
src/client/ua_client_highlevel_subscriptions.c

@@ -424,7 +424,8 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
                     continue;
                     continue;
                 }
                 }
 
 
-                mon->handler.dataChangeHandler(mon->monitoredItemId, &mitemNot->value, mon->handlerContext);
+                mon->handler.dataChangeHandler(client, mon->monitoredItemId,
+                                               &mitemNot->value, mon->handlerContext);
             }
             }
             continue;
             continue;
         }
         }
@@ -457,7 +458,7 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
                     continue;
                     continue;
                 }
                 }
 
 
-                mon->handler.eventHandler(mon->monitoredItemId, eventFieldList->eventFieldsSize,
+                mon->handler.eventHandler(client, mon->monitoredItemId, eventFieldList->eventFieldsSize,
                                           eventFieldList->eventFields, mon->handlerContext);
                                           eventFieldList->eventFields, mon->handlerContext);
             }
             }
         }
         }

+ 3 - 0
src/client/ua_client_internal.h

@@ -118,6 +118,9 @@ struct UA_Client {
 #endif
 #endif
 };
 };
 
 
+void
+setClientState(UA_Client *client, UA_ClientState state);
+
 UA_StatusCode
 UA_StatusCode
 UA_Client_connectInternal(UA_Client *client, const char *endpointUrl,
 UA_Client_connectInternal(UA_Client *client, const char *endpointUrl,
                           UA_Boolean endpointsHandshake, UA_Boolean createNewSession);
                           UA_Boolean endpointsHandshake, UA_Boolean createNewSession);

+ 2 - 2
src/server/ua_mdns.c

@@ -111,7 +111,7 @@ mdns_record_add_or_get(UA_Server *server, const char *record, const char *server
     // todo: malloc may fail: return a statuscode
     // todo: malloc may fail: return a statuscode
     listEntry->serverOnNetwork.serverName.data = (UA_Byte*)UA_malloc(serverNameLen);
     listEntry->serverOnNetwork.serverName.data = (UA_Byte*)UA_malloc(serverNameLen);
     memcpy(listEntry->serverOnNetwork.serverName.data, serverName, serverNameLen);
     memcpy(listEntry->serverOnNetwork.serverName.data, serverName, serverNameLen);
-    server->serverOnNetworkRecordIdCounter = UA_atomic_add(&server->serverOnNetworkRecordIdCounter, 1);
+    UA_atomic_addUInt32(&server->serverOnNetworkRecordIdCounter, 1);
     if(server->serverOnNetworkRecordIdCounter == 0)
     if(server->serverOnNetworkRecordIdCounter == 0)
         server->serverOnNetworkRecordIdLastReset = UA_DateTime_now();
         server->serverOnNetworkRecordIdLastReset = UA_DateTime_now();
 
 
@@ -169,7 +169,7 @@ mdns_record_remove(UA_Server *server, const char *record,
     server->serverOnNetworkSize--;
     server->serverOnNetworkSize--;
     UA_free(entry);
     UA_free(entry);
 #else
 #else
-    server->serverOnNetworkSize = uatomic_add_return(&server->serverOnNetworkSize, -1);
+    UA_atomic_subSize(&server->serverOnNetworkSize, 1);
     UA_Server_delayedCallback(server, delayedFree, entry);
     UA_Server_delayedCallback(server, delayedFree, entry);
 #endif
 #endif
 }
 }

+ 2 - 2
src/server/ua_securechannel_manager.c

@@ -59,7 +59,7 @@ removeSecureChannel(UA_SecureChannelManager *cm, channel_list_entry *entry) {
 
 
     /* Detach the channel and make the capacity available */
     /* Detach the channel and make the capacity available */
     LIST_REMOVE(entry, pointers);
     LIST_REMOVE(entry, pointers);
-    UA_atomic_add(&cm->currentChannelCount, (UA_UInt32)-1);
+    UA_atomic_subUInt32(&cm->currentChannelCount, 1);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
@@ -134,7 +134,7 @@ UA_SecureChannelManager_create(UA_SecureChannelManager *const cm, UA_Connection
     entry->channel.securityToken.revisedLifetime = cm->server->config.maxSecurityTokenLifetime;
     entry->channel.securityToken.revisedLifetime = cm->server->config.maxSecurityTokenLifetime;
 
 
     LIST_INSERT_HEAD(&cm->channels, entry, pointers);
     LIST_INSERT_HEAD(&cm->channels, entry, pointers);
-    UA_atomic_add(&cm->currentChannelCount, 1);
+    UA_atomic_addUInt32(&cm->currentChannelCount, 1);
     UA_Connection_attachSecureChannel(connection, &entry->channel);
     UA_Connection_attachSecureChannel(connection, &entry->channel);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }

+ 3 - 2
src/server/ua_server.c

@@ -145,8 +145,9 @@ void UA_Server_delete(UA_Server *server) {
 #endif
 #endif
 
 
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
+    pthread_mutex_destroy(&server->dispatchQueue_accessMutex);
     pthread_cond_destroy(&server->dispatchQueue_condition);
     pthread_cond_destroy(&server->dispatchQueue_condition);
-    pthread_mutex_destroy(&server->dispatchQueue_mutex);
+    pthread_mutex_destroy(&server->dispatchQueue_conditionMutex);
 #endif
 #endif
 
 
     /* Delete the timed work */
     /* Delete the timed work */
@@ -211,7 +212,7 @@ UA_Server_new(const UA_ServerConfig *config) {
 
 
     /* Initialized the dispatch queue for worker threads */
     /* Initialized the dispatch queue for worker threads */
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
-    cds_wfcq_init(&server->dispatchQueue_head, &server->dispatchQueue_tail);
+    SIMPLEQ_INIT(&server->dispatchQueue);
 #endif
 #endif
 
 
     /* Create Namespaces 0 and 1 */
     /* Create Namespaces 0 and 1 */

+ 11 - 8
src/server/ua_server_internal.h

@@ -28,13 +28,17 @@ extern "C" {
 
 
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
 
 
-/* TODO: Don't depend on liburcu */
-#include <urcu.h>
-#include <urcu/lfstack.h>
+#include <pthread.h>
 
 
 struct UA_Worker;
 struct UA_Worker;
 typedef struct UA_Worker UA_Worker;
 typedef struct UA_Worker UA_Worker;
 
 
+struct UA_WorkerCallback;
+typedef struct UA_WorkerCallback UA_WorkerCallback;
+
+SIMPLEQ_HEAD(UA_DispatchQueue, UA_WorkerCallback);
+typedef struct UA_DispatchQueue UA_DispatchQueue;
+
 #endif /* UA_ENABLE_MULTITHREADING */
 #endif /* UA_ENABLE_MULTITHREADING */
 
 
 #ifdef UA_ENABLE_DISCOVERY
 #ifdef UA_ENABLE_DISCOVERY
@@ -126,12 +130,11 @@ struct UA_Server {
 
 
     /* Worker threads */
     /* Worker threads */
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
-    /* Dispatch queue head for the worker threads (the tail should not be in the same cache line) */
-    struct cds_wfcq_head dispatchQueue_head;
     UA_Worker *workers; /* there are nThread workers in a running server */
     UA_Worker *workers; /* there are nThread workers in a running server */
+    UA_DispatchQueue dispatchQueue; /* Dispatch queue for the worker threads */
+    pthread_mutex_t dispatchQueue_accessMutex; /* mutex for access to queue */
     pthread_cond_t dispatchQueue_condition; /* so the workers don't spin if the queue is empty */
     pthread_cond_t dispatchQueue_condition; /* so the workers don't spin if the queue is empty */
-    pthread_mutex_t dispatchQueue_mutex; /* mutex for access to condition variable */
-    struct cds_wfcq_tail dispatchQueue_tail; /* Dispatch queue tail for the worker threads */
+    pthread_mutex_t dispatchQueue_conditionMutex; /* mutex for access to condition variable */
 #endif
 #endif
 
 
     /* For bootstrapping, omit some consistency checks, creating a reference to
     /* For bootstrapping, omit some consistency checks, creating a reference to
@@ -276,7 +279,7 @@ compatibleValueRankArrayDimensions(UA_Int32 valueRank, size_t arrayDimensionsSiz
 
 
 UA_Boolean
 UA_Boolean
 compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
 compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
-                   const UA_NodeId *constraintDataType);
+                   const UA_NodeId *constraintDataType, UA_Boolean isValue);
 
 
 UA_Boolean
 UA_Boolean
 compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank);
 compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank);

+ 34 - 29
src/server/ua_server_worker.c

@@ -44,15 +44,16 @@ struct UA_Worker {
                  sizeof(UA_UInt32) - sizeof(UA_Boolean)];
                  sizeof(UA_UInt32) - sizeof(UA_Boolean)];
 };
 };
 
 
-typedef struct {
-    struct cds_wfcq_node node;
+struct UA_WorkerCallback {
+    SIMPLEQ_ENTRY(UA_WorkerCallback) next;
     UA_ServerCallback callback;
     UA_ServerCallback callback;
     void *data;
     void *data;
 
 
     UA_Boolean delayed;         /* Is it a delayed callback? */
     UA_Boolean delayed;         /* Is it a delayed callback? */
     UA_Boolean countersSampled; /* Have the worker counters been sampled? */
     UA_Boolean countersSampled; /* Have the worker counters been sampled? */
     UA_UInt32 workerCounters[]; /* Counter value for each worker */
     UA_UInt32 workerCounters[]; /* Counter value for each worker */
-} WorkerCallback;
+};
+typedef struct UA_WorkerCallback WorkerCallback;
 
 
 /* Forward Declaration */
 /* Forward Declaration */
 static void
 static void
@@ -69,16 +70,19 @@ workerLoop(UA_Worker *worker) {
     UA_random_seed((uintptr_t)worker);
     UA_random_seed((uintptr_t)worker);
 
 
     while(*running) {
     while(*running) {
-        UA_atomic_add(counter, 1);
-        WorkerCallback *dc = (WorkerCallback*)
-            cds_wfcq_dequeue_blocking(&server->dispatchQueue_head,
-                                      &server->dispatchQueue_tail);
+        UA_atomic_addUInt32(counter, 1);
+        pthread_mutex_lock(&server->dispatchQueue_accessMutex);
+        WorkerCallback *dc = SIMPLEQ_FIRST(&server->dispatchQueue);
+        if(dc) {
+            SIMPLEQ_REMOVE_HEAD(&server->dispatchQueue, next);
+        }
+        pthread_mutex_unlock(&server->dispatchQueue_accessMutex);
         if(!dc) {
         if(!dc) {
             /* Nothing to do. Sleep until a callback is dispatched */
             /* Nothing to do. Sleep until a callback is dispatched */
-            pthread_mutex_lock(&server->dispatchQueue_mutex);
+            pthread_mutex_lock(&server->dispatchQueue_conditionMutex);
             pthread_cond_wait(&server->dispatchQueue_condition,
             pthread_cond_wait(&server->dispatchQueue_condition,
-                              &server->dispatchQueue_mutex);
-            pthread_mutex_unlock(&server->dispatchQueue_mutex);
+                              &server->dispatchQueue_conditionMutex);
+            pthread_mutex_unlock(&server->dispatchQueue_conditionMutex);
             continue;
             continue;
         }
         }
 
 
@@ -98,14 +102,14 @@ workerLoop(UA_Worker *worker) {
 
 
 static void
 static void
 emptyDispatchQueue(UA_Server *server) {
 emptyDispatchQueue(UA_Server *server) {
-    while(!cds_wfcq_empty(&server->dispatchQueue_head,
-                          &server->dispatchQueue_tail)) {
-        WorkerCallback *dc = (WorkerCallback*)
-            cds_wfcq_dequeue_blocking(&server->dispatchQueue_head,
-                                      &server->dispatchQueue_tail);
+    pthread_mutex_lock(&server->dispatchQueue_accessMutex);
+    WorkerCallback *dc;
+    while((dc = SIMPLEQ_FIRST(&server->dispatchQueue)) != NULL) {
+        SIMPLEQ_REMOVE_HEAD(&server->dispatchQueue, next);
         dc->callback(server, dc->data);
         dc->callback(server, dc->data);
         UA_free(dc);
         UA_free(dc);
     }
     }
+    pthread_mutex_unlock(&server->dispatchQueue_accessMutex);
 }
 }
 
 
 #endif
 #endif
@@ -135,9 +139,9 @@ UA_Server_workerCallback(UA_Server *server, UA_ServerCallback callback,
     dc->callback = callback;
     dc->callback = callback;
     dc->data = data;
     dc->data = data;
     dc->delayed = false;
     dc->delayed = false;
-    cds_wfcq_node_init(&dc->node);
-    cds_wfcq_enqueue(&server->dispatchQueue_head,
-                     &server->dispatchQueue_tail, &dc->node);
+    pthread_mutex_lock(&server->dispatchQueue_accessMutex);
+    SIMPLEQ_INSERT_TAIL(&server->dispatchQueue, dc, next);
+    pthread_mutex_unlock(&server->dispatchQueue_accessMutex);
 
 
     /* Wake up sleeping workers */
     /* Wake up sleeping workers */
     pthread_cond_broadcast(&server->dispatchQueue_condition);
     pthread_cond_broadcast(&server->dispatchQueue_condition);
@@ -210,9 +214,9 @@ UA_Server_delayedCallback(UA_Server *server, UA_ServerCallback callback,
     dc->data = data;
     dc->data = data;
     dc->delayed = true;
     dc->delayed = true;
     dc->countersSampled = false;
     dc->countersSampled = false;
-    cds_wfcq_node_init(&dc->node);
-    cds_wfcq_enqueue(&server->dispatchQueue_head,
-                     &server->dispatchQueue_tail, &dc->node);
+    pthread_mutex_lock(&server->dispatchQueue_accessMutex);
+    SIMPLEQ_INSERT_TAIL(&server->dispatchQueue, dc, next);
+    pthread_mutex_unlock(&server->dispatchQueue_accessMutex);
 
 
     /* Wake up sleeping workers */
     /* Wake up sleeping workers */
     pthread_cond_broadcast(&server->dispatchQueue_condition);
     pthread_cond_broadcast(&server->dispatchQueue_condition);
@@ -229,9 +233,9 @@ processDelayedCallback(UA_Server *server, WorkerCallback *dc) {
         dc->countersSampled = true;
         dc->countersSampled = true;
 
 
         /* Re-add to the dispatch queue */
         /* Re-add to the dispatch queue */
-        cds_wfcq_node_init(&dc->node);
-        cds_wfcq_enqueue(&server->dispatchQueue_head,
-                         &server->dispatchQueue_tail, &dc->node);
+        pthread_mutex_lock(&server->dispatchQueue_accessMutex);
+        SIMPLEQ_INSERT_TAIL(&server->dispatchQueue, dc, next);
+        pthread_mutex_unlock(&server->dispatchQueue_accessMutex);
 
 
         /* Wake up sleeping workers */
         /* Wake up sleeping workers */
         pthread_cond_broadcast(&server->dispatchQueue_condition);
         pthread_cond_broadcast(&server->dispatchQueue_condition);
@@ -251,9 +255,9 @@ processDelayedCallback(UA_Server *server, WorkerCallback *dc) {
      * TODO: What is the impact of this loop?
      * TODO: What is the impact of this loop?
      * Can we add a small delay here? */
      * Can we add a small delay here? */
     if(!ready) {
     if(!ready) {
-        cds_wfcq_node_init(&dc->node);
-        cds_wfcq_enqueue(&server->dispatchQueue_head,
-                         &server->dispatchQueue_tail, &dc->node);
+        pthread_mutex_lock(&server->dispatchQueue_accessMutex);
+        SIMPLEQ_INSERT_TAIL(&server->dispatchQueue, dc, next);
+        pthread_mutex_unlock(&server->dispatchQueue_accessMutex);
 
 
         /* Wake up sleeping workers */
         /* Wake up sleeping workers */
         pthread_cond_broadcast(&server->dispatchQueue_condition);
         pthread_cond_broadcast(&server->dispatchQueue_condition);
@@ -301,8 +305,9 @@ UA_Server_run_startup(UA_Server *server) {
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
     UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
     UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
                 "Spinning up %u worker thread(s)", server->config.nThreads);
                 "Spinning up %u worker thread(s)", server->config.nThreads);
-    pthread_cond_init(&server->dispatchQueue_condition, 0);
-    pthread_mutex_init(&server->dispatchQueue_mutex, 0);
+    pthread_mutex_init(&server->dispatchQueue_accessMutex, NULL);
+    pthread_cond_init(&server->dispatchQueue_condition, NULL);
+    pthread_mutex_init(&server->dispatchQueue_conditionMutex, NULL);
     server->workers = (UA_Worker*)UA_malloc(server->config.nThreads * sizeof(UA_Worker));
     server->workers = (UA_Worker*)UA_malloc(server->config.nThreads * sizeof(UA_Worker));
     if(!server->workers)
     if(!server->workers)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;

+ 23 - 16
src/server/ua_services_attribute.c

@@ -536,7 +536,7 @@ static const UA_NodeId enumNodeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ENUMERA
 
 
 UA_Boolean
 UA_Boolean
 compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
 compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
-                   const UA_NodeId *constraintDataType) {
+                   const UA_NodeId *constraintDataType, UA_Boolean isValue) {
     /* Do not allow empty datatypes */
     /* Do not allow empty datatypes */
     if(UA_NodeId_isNull(dataType))
     if(UA_NodeId_isNull(dataType))
        return false;
        return false;
@@ -545,6 +545,10 @@ compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
     if(UA_NodeId_isNull(constraintDataType))
     if(UA_NodeId_isNull(constraintDataType))
         return true;
         return true;
 
 
+    /* Same datatypes */
+    if (UA_NodeId_equal(dataType, constraintDataType))
+        return true;
+
     /* Variant allows any subtype */
     /* Variant allows any subtype */
     if(UA_NodeId_equal(constraintDataType, &UA_TYPES[UA_TYPES_VARIANT].typeId))
     if(UA_NodeId_equal(constraintDataType, &UA_TYPES[UA_TYPES_VARIANT].typeId))
         return true;
         return true;
@@ -553,22 +557,25 @@ compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
     if(isNodeInTree(&server->config.nodestore, dataType, constraintDataType, &subtypeId, 1))
     if(isNodeInTree(&server->config.nodestore, dataType, constraintDataType, &subtypeId, 1))
         return true;
         return true;
 
 
-    /* If value is a built-in type: The target data type may be a sub type of
-     * the built-in type. (e.g. UtcTime is sub-type of DateTime and has a
-     * DateTime value). A type is builtin if its NodeId is in Namespace 0 and
-     * has a numeric identifier <= 25 (DiagnosticInfo) */
-    if(dataType->namespaceIndex == 0 &&
-       dataType->identifierType == UA_NODEIDTYPE_NUMERIC &&
-       dataType->identifier.numeric <= 25 &&
-       isNodeInTree(&server->config.nodestore, constraintDataType,
-                    dataType, &subtypeId, 1))
-        return true;
-
     /* Enum allows Int32 (only) */
     /* Enum allows Int32 (only) */
     if(UA_NodeId_equal(dataType, &UA_TYPES[UA_TYPES_INT32].typeId) &&
     if(UA_NodeId_equal(dataType, &UA_TYPES[UA_TYPES_INT32].typeId) &&
        isNodeInTree(&server->config.nodestore, constraintDataType, &enumNodeId, &subtypeId, 1))
        isNodeInTree(&server->config.nodestore, constraintDataType, &enumNodeId, &subtypeId, 1))
         return true;
         return true;
 
 
+    /* More checks for the data type of real values (variants) */
+    if(isValue) {
+        /* If value is a built-in type: The target data type may be a sub type of
+         * the built-in type. (e.g. UtcTime is sub-type of DateTime and has a
+         * DateTime value). A type is builtin if its NodeId is in Namespace 0 and
+         * has a numeric identifier <= 25 (DiagnosticInfo) */
+        if(dataType->namespaceIndex == 0 &&
+           dataType->identifierType == UA_NODEIDTYPE_NUMERIC &&
+           dataType->identifier.numeric <= 25 &&
+           isNodeInTree(&server->config.nodestore, constraintDataType,
+                        dataType, &subtypeId, 1))
+            return true;
+    }
+
     return false;
     return false;
 }
 }
 
 
@@ -592,7 +599,7 @@ compatibleValueRankArrayDimensions(UA_Int32 valueRank, size_t arrayDimensionsSiz
             return false;
             return false;
         break;
         break;
     default: /* >= 1: the value is an array with the specified number of dimensions */
     default: /* >= 1: the value is an array with the specified number of dimensions */
-        if(valueRank < 0)
+        if(valueRank < (UA_Int32) 0)
             return false;
             return false;
         /* Must hold if the array has a defined length. Null arrays (length -1)
         /* Must hold if the array has a defined length. Null arrays (length -1)
          * need to be caught before. */
          * need to be caught before. */
@@ -617,7 +624,7 @@ compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank) {
             return false;
             return false;
         break;
         break;
     case 0: /* the value is an array with one or more dimensions */
     case 0: /* the value is an array with one or more dimensions */
-        if(valueRank < 0)
+        if(valueRank < (UA_Int32) 0)
             return false;
             return false;
         break;
         break;
     default: /* >= 1: the value is an array with the specified number of dimensions */
     default: /* >= 1: the value is an array with the specified number of dimensions */
@@ -696,7 +703,7 @@ compatibleValue(UA_Server *server, const UA_NodeId *targetDataTypeId,
 
 
     /* Has the value a subtype of the required type? BaseDataType (Variant) can
     /* Has the value a subtype of the required type? BaseDataType (Variant) can
      * be anything... */
      * be anything... */
-    if(!compatibleDataType(server, &value->type->typeId, targetDataTypeId))
+    if(!compatibleDataType(server, &value->type->typeId, targetDataTypeId, true))
         return false;
         return false;
 
 
     /* Array dimensions are checked later when writing the range */
     /* Array dimensions are checked later when writing the range */
@@ -872,7 +879,7 @@ writeDataTypeAttribute(UA_Server *server, UA_Session *session,
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
 
 
     /* Does the new type match the constraints of the variabletype? */
     /* Does the new type match the constraints of the variabletype? */
-    if(!compatibleDataType(server, dataType, &type->dataType))
+    if(!compatibleDataType(server, dataType, &type->dataType, false))
         return UA_STATUSCODE_BADTYPEMISMATCH;
         return UA_STATUSCODE_BADTYPEMISMATCH;
 
 
     /* Check if the current value would match the new type */
     /* Check if the current value would match the new type */

+ 3 - 3
src/server/ua_services_discovery.c

@@ -461,7 +461,7 @@ process_RegisterServer(UA_Server *server, UA_Session *session,
         UA_free(registeredServer_entry);
         UA_free(registeredServer_entry);
         server->registeredServersSize--;
         server->registeredServersSize--;
 #else
 #else
-        server->registeredServersSize = uatomic_add_return(&server->registeredServersSize, -1);
+        UA_atomic_subSize(&server->registeredServersSize, 1);
         UA_Server_delayedCallback(server, freeEntry, registeredServer_entry);
         UA_Server_delayedCallback(server, freeEntry, registeredServer_entry);
 #endif
 #endif
         responseHeader->serviceResult = UA_STATUSCODE_GOOD;
         responseHeader->serviceResult = UA_STATUSCODE_GOOD;
@@ -485,7 +485,7 @@ process_RegisterServer(UA_Server *server, UA_Session *session,
 #ifndef UA_ENABLE_MULTITHREADING
 #ifndef UA_ENABLE_MULTITHREADING
         server->registeredServersSize++;
         server->registeredServersSize++;
 #else
 #else
-        server->registeredServersSize = uatomic_add_return(&server->registeredServersSize, 1);
+        UA_atomic_addSize(&server->registeredServersSize, 1);
 #endif
 #endif
 
 
         if(server->registerServerCallback)
         if(server->registerServerCallback)
@@ -583,7 +583,7 @@ void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic) {
             UA_free(current);
             UA_free(current);
             server->registeredServersSize--;
             server->registeredServersSize--;
 #else
 #else
-            server->registeredServersSize = uatomic_add_return(&server->registeredServersSize, -1);
+            UA_atomic_subSize(&server->registeredServersSize, 1);
             UA_Server_delayedCallback(server, freeEntry, current);
             UA_Server_delayedCallback(server, freeEntry, current);
 #endif
 #endif
         }
         }

+ 1 - 1
src/server/ua_services_nodemanagement.c

@@ -156,7 +156,7 @@ typeCheckVariableNode(UA_Server *server, UA_Session *session,
         return retval;
         return retval;
 
 
     /* Check the datatype against the vt */
     /* Check the datatype against the vt */
-    if(!compatibleDataType(server, &node->dataType, &vt->dataType))
+    if(!compatibleDataType(server, &node->dataType, &vt->dataType, false))
         return UA_STATUSCODE_BADTYPEMISMATCH;
         return UA_STATUSCODE_BADTYPEMISMATCH;
 
 
     /* Get the array dimensions */
     /* Get the array dimensions */

+ 22 - 3
src/server/ua_session.c

@@ -3,11 +3,13 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
  *
  *
  *    Copyright 2018 (c) Julius Pfrommer, Fraunhofer IOSB
  *    Copyright 2018 (c) Julius Pfrommer, Fraunhofer IOSB
+ *    Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA
  */
  */
 
 
 #include "ua_session.h"
 #include "ua_session.h"
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 #ifdef UA_ENABLE_SUBSCRIPTIONS
-#include "server/ua_subscription.h"
+#include "ua_subscription.h"
+#include "ua_server_internal.h"
 #endif
 #endif
 
 
 UA_Session adminSession = {
 UA_Session adminSession = {
@@ -102,6 +104,14 @@ void UA_Session_addSubscription(UA_Session *session, UA_Subscription *newSubscri
     LIST_INSERT_HEAD(&session->serverSubscriptions, newSubscription, listEntry);
     LIST_INSERT_HEAD(&session->serverSubscriptions, newSubscription, listEntry);
 }
 }
 
 
+/* Delayed callback to free the subscription memory */
+static void
+removeSubscriptionCallback(UA_Server *server, void *data) {
+    UA_Subscription *sub = (UA_Subscription*)data;
+    UA_Subscription_deleteMembers(sub, server);
+    UA_free(sub);
+}
+
 UA_StatusCode
 UA_StatusCode
 UA_Session_deleteSubscription(UA_Server *server, UA_Session *session,
 UA_Session_deleteSubscription(UA_Server *server, UA_Session *session,
                               UA_UInt32 subscriptionId) {
                               UA_UInt32 subscriptionId) {
@@ -109,9 +119,18 @@ UA_Session_deleteSubscription(UA_Server *server, UA_Session *session,
     if(!sub)
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
 
 
+    /* Add a delayed callback to remove the subscription when the currently
+     * scheduled jobs have completed */
+    UA_StatusCode retval = UA_Server_delayedCallback(server, removeSubscriptionCallback, sub);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_WARNING_SESSION(server->config.logger, session,
+                       "Could not remove subscription with error code %s",
+                       UA_StatusCode_name(retval));
+        return retval; /* Try again next time */
+    }
+
     LIST_REMOVE(sub, listEntry);
     LIST_REMOVE(sub, listEntry);
-    UA_Subscription_deleteMembers(sub, server);
-    UA_free(sub);
+
     if(session->numSubscriptions > 0) {
     if(session->numSubscriptions > 0) {
         session->numSubscriptions--;
         session->numSubscriptions--;
     }
     }

+ 2 - 2
src/server/ua_session_manager.c

@@ -58,7 +58,7 @@ removeSession(UA_SessionManager *sm, session_list_entry *sentry) {
     /* Detach the session from the session manager and make the capacity
     /* Detach the session from the session manager and make the capacity
      * available */
      * available */
     LIST_REMOVE(sentry, pointers);
     LIST_REMOVE(sentry, pointers);
-    UA_atomic_add(&sm->currentSessionCount, (UA_UInt32)-1);
+    UA_atomic_subUInt32(&sm->currentSessionCount, 1);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
@@ -141,7 +141,7 @@ UA_SessionManager_createSession(UA_SessionManager *sm, UA_SecureChannel *channel
     if(!newentry)
     if(!newentry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
 
-    UA_atomic_add(&sm->currentSessionCount, 1);
+    UA_atomic_addUInt32(&sm->currentSessionCount, 1);
     UA_Session_init(&newentry->session);
     UA_Session_init(&newentry->session);
     newentry->session.sessionId = UA_NODEID_GUID(1, UA_Guid_random());
     newentry->session.sessionId = UA_NODEID_GUID(1, UA_Guid_random());
     newentry->session.header.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random());
     newentry->session.header.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random());

+ 36 - 25
src/ua_securechannel.c

@@ -30,7 +30,7 @@
     UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH)
     UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH)
 
 
 const UA_ByteString
 const UA_ByteString
-    UA_SECURITY_POLICY_NONE_URI = {47, (UA_Byte *) "http://opcfoundation.org/UA/SecurityPolicy#None"};
+    UA_SECURITY_POLICY_NONE_URI = {47, (UA_Byte *)"http://opcfoundation.org/UA/SecurityPolicy#None"};
 
 
 #ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS
 #ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS
 UA_THREAD_LOCAL UA_StatusCode decrypt_verifySignatureFailure;
 UA_THREAD_LOCAL UA_StatusCode decrypt_verifySignatureFailure;
@@ -50,7 +50,19 @@ UA_SecureChannel_init(UA_SecureChannel *channel,
     channel->state = UA_SECURECHANNELSTATE_FRESH;
     channel->state = UA_SECURECHANNELSTATE_FRESH;
     channel->securityPolicy = securityPolicy;
     channel->securityPolicy = securityPolicy;
 
 
-    UA_StatusCode retval = securityPolicy->channelModule.
+    UA_StatusCode retval;
+    if(channel->securityPolicy->certificateVerification != NULL) {
+        retval = channel->securityPolicy->certificateVerification->
+            verifyCertificate(channel->securityPolicy->certificateVerification->context, remoteCertificate);
+
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    } else {
+        UA_LOG_WARNING(channel->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, "No PKI plugin set. "
+            "Accepting all certificates");
+    }
+
+    retval = securityPolicy->channelModule.
         newContext(securityPolicy, remoteCertificate, &channel->channelContext);
         newContext(securityPolicy, remoteCertificate, &channel->channelContext);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
@@ -130,7 +142,7 @@ UA_SecureChannel_generateNewKeys(UA_SecureChannel *channel) {
         getLocalEncryptionKeyLength(securityPolicy, channel->channelContext);
         getLocalEncryptionKeyLength(securityPolicy, channel->channelContext);
     const size_t buffSize = symmetricModule->encryptionBlockSize +
     const size_t buffSize = symmetricModule->encryptionBlockSize +
                             symmetricModule->signingKeyLength + encryptionKeyLength;
                             symmetricModule->signingKeyLength + encryptionKeyLength;
-    UA_ByteString buffer = {buffSize, (UA_Byte *) UA_alloca(buffSize)};
+    UA_ByteString buffer = {buffSize, (UA_Byte *)UA_alloca(buffSize)};
 
 
     /* Remote keys */
     /* Remote keys */
     UA_StatusCode retval = symmetricModule->generateKey(securityPolicy, &channel->localNonce,
     UA_StatusCode retval = symmetricModule->generateKey(securityPolicy, &channel->localNonce,
@@ -205,9 +217,9 @@ calculatePaddingAsym(const UA_SecurityPolicy *securityPolicy, const void *channe
         ++paddingBytes;
         ++paddingBytes;
     size_t padding = (plainTextBlockSize - ((bytesToWrite + signatureSize + paddingBytes) %
     size_t padding = (plainTextBlockSize - ((bytesToWrite + signatureSize + paddingBytes) %
                                             plainTextBlockSize));
                                             plainTextBlockSize));
-    *paddingSize = (UA_Byte) (padding & 0xff);
-    *extraPaddingSize = (UA_Byte) (padding >> 8);
-    return (UA_UInt16) padding;
+    *paddingSize = (UA_Byte)(padding & 0xff);
+    *extraPaddingSize = (UA_Byte)(padding >> 8);
+    return (UA_UInt16)padding;
 }
 }
 
 
 static size_t
 static size_t
@@ -230,7 +242,7 @@ hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start, const UA_Byt
 
 
     /* Add the SecurityHeaderLength */
     /* Add the SecurityHeaderLength */
     *buf_start += calculateAsymAlgSecurityHeaderLength(channel);
     *buf_start += calculateAsymAlgSecurityHeaderLength(channel);
-    size_t potentialEncryptionMaxSize = (size_t) (*buf_end - *buf_start) + UA_SEQUENCE_HEADER_LENGTH;
+    size_t potentialEncryptionMaxSize = (size_t)(*buf_end - *buf_start) + UA_SEQUENCE_HEADER_LENGTH;
 
 
     /* Hide bytes for signature and padding */
     /* Hide bytes for signature and padding */
     if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
     if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
@@ -290,7 +302,7 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 r
             &buf.data[UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH +
             &buf.data[UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH +
                       UA_SEQUENCE_HEADER_LENGTH + securityHeaderLength];
                       UA_SEQUENCE_HEADER_LENGTH + securityHeaderLength];
         const size_t bytesToWrite =
         const size_t bytesToWrite =
-            (uintptr_t) buf_pos - (uintptr_t) buf_body_start + UA_SEQUENCE_HEADER_LENGTH;
+            (uintptr_t)buf_pos - (uintptr_t)buf_body_start + UA_SEQUENCE_HEADER_LENGTH;
         UA_Byte paddingSize = 0;
         UA_Byte paddingSize = 0;
         UA_Byte extraPaddingSize = 0;
         UA_Byte extraPaddingSize = 0;
         UA_UInt16 totalPaddingSize =
         UA_UInt16 totalPaddingSize =
@@ -310,7 +322,7 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 r
     }
     }
 
 
     /* The total message length */
     /* The total message length */
-    size_t pre_sig_length = (uintptr_t) buf_pos - (uintptr_t) buf.data;
+    size_t pre_sig_length = (uintptr_t)buf_pos - (uintptr_t)buf.data;
     size_t total_length = pre_sig_length;
     size_t total_length = pre_sig_length;
     if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
     if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
        channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
@@ -344,7 +356,7 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 r
 
 
     UA_SequenceHeader seqHeader;
     UA_SequenceHeader seqHeader;
     seqHeader.requestId = requestId;
     seqHeader.requestId = requestId;
-    seqHeader.sequenceNumber = UA_atomic_add(&channel->sendSequenceNumber, 1);
+    seqHeader.sequenceNumber = UA_atomic_addUInt32(&channel->sendSequenceNumber, 1);
     retval |= UA_encodeBinary(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
     retval |= UA_encodeBinary(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
                               &header_pos, &buf_end, NULL, NULL);
                               &header_pos, &buf_end, NULL, NULL);
 
 
@@ -399,12 +411,12 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 r
 static UA_UInt16
 static UA_UInt16
 calculatePaddingSym(const UA_SecurityPolicy *securityPolicy, const void *channelContext,
 calculatePaddingSym(const UA_SecurityPolicy *securityPolicy, const void *channelContext,
                     size_t bytesToWrite, UA_Byte *paddingSize, UA_Byte *extraPaddingSize) {
                     size_t bytesToWrite, UA_Byte *paddingSize, UA_Byte *extraPaddingSize) {
-    UA_UInt16 padding = (UA_UInt16) (securityPolicy->symmetricModule.encryptionBlockSize -
-                                     ((bytesToWrite + securityPolicy->symmetricModule.cryptoModule.
-                                         getLocalSignatureSize(securityPolicy, channelContext) + 1) %
-                                      securityPolicy->symmetricModule.encryptionBlockSize));
-    *paddingSize = (UA_Byte) padding;
-    *extraPaddingSize = (UA_Byte) (padding >> 8);
+    UA_UInt16 padding = (UA_UInt16)(securityPolicy->symmetricModule.encryptionBlockSize -
+                                    ((bytesToWrite + securityPolicy->symmetricModule.cryptoModule.
+                                        getLocalSignatureSize(securityPolicy, channelContext) + 1) %
+                                     securityPolicy->symmetricModule.encryptionBlockSize));
+    *paddingSize = (UA_Byte)padding;
+    *extraPaddingSize = (UA_Byte)(padding >> 8);
     return padding;
     return padding;
 }
 }
 
 
@@ -440,7 +452,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
     /* Will this chunk surpass the capacity of the SecureChannel for the message? */
     /* Will this chunk surpass the capacity of the SecureChannel for the message? */
     UA_Byte *buf_body_start = mc->messageBuffer.data + UA_SECURE_MESSAGE_HEADER_LENGTH;
     UA_Byte *buf_body_start = mc->messageBuffer.data + UA_SECURE_MESSAGE_HEADER_LENGTH;
     const UA_Byte *buf_body_end = mc->buf_pos;
     const UA_Byte *buf_body_end = mc->buf_pos;
-    size_t bodyLength = (uintptr_t) buf_body_end - (uintptr_t) buf_body_start;
+    size_t bodyLength = (uintptr_t)buf_body_end - (uintptr_t)buf_body_start;
     mc->messageSizeSoFar += bodyLength;
     mc->messageSizeSoFar += bodyLength;
     mc->chunksSoFar++;
     mc->chunksSoFar++;
     if(mc->messageSizeSoFar > connection->remoteConf.maxMessageSize &&
     if(mc->messageSizeSoFar > connection->remoteConf.maxMessageSize &&
@@ -476,7 +488,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
     }
     }
 
 
     /* The total message length */
     /* The total message length */
-    size_t pre_sig_length = (uintptr_t) (mc->buf_pos) - (uintptr_t) mc->messageBuffer.data;
+    size_t pre_sig_length = (uintptr_t)(mc->buf_pos) - (uintptr_t)mc->messageBuffer.data;
     size_t total_length = pre_sig_length;
     size_t total_length = pre_sig_length;
     if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
     if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
        channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
@@ -490,7 +502,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
     UA_SecureConversationMessageHeader respHeader;
     UA_SecureConversationMessageHeader respHeader;
     respHeader.secureChannelId = channel->securityToken.channelId;
     respHeader.secureChannelId = channel->securityToken.channelId;
     respHeader.messageHeader.messageTypeAndChunkType = mc->messageType;
     respHeader.messageHeader.messageTypeAndChunkType = mc->messageType;
-    respHeader.messageHeader.messageSize = (UA_UInt32) total_length;
+    respHeader.messageHeader.messageSize = (UA_UInt32)total_length;
     if(mc->final)
     if(mc->final)
         respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL;
         respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL;
     else
     else
@@ -506,7 +518,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
 
 
     UA_SequenceHeader seqHeader;
     UA_SequenceHeader seqHeader;
     seqHeader.requestId = mc->requestId;
     seqHeader.requestId = mc->requestId;
-    seqHeader.sequenceNumber = UA_atomic_add(&channel->sendSequenceNumber, 1);
+    seqHeader.sequenceNumber = UA_atomic_addUInt32(&channel->sendSequenceNumber, 1);
     res |= UA_encodeBinary(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
     res |= UA_encodeBinary(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
                            &header_pos, &mc->buf_end, NULL, NULL);
                            &header_pos, &mc->buf_end, NULL, NULL);
 
 
@@ -545,7 +557,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
 static UA_StatusCode
 static UA_StatusCode
 sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos, const UA_Byte **buf_end) {
 sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos, const UA_Byte **buf_end) {
     /* Set buf values from encoding in the messagecontext */
     /* Set buf values from encoding in the messagecontext */
-    UA_MessageContext *mc = (UA_MessageContext *) data;
+    UA_MessageContext *mc = (UA_MessageContext *)data;
     mc->buf_pos = *buf_pos;
     mc->buf_pos = *buf_pos;
     mc->buf_end = *buf_end;
     mc->buf_end = *buf_end;
 
 
@@ -695,7 +707,7 @@ UA_SecureChannel_appendChunk(UA_SecureChannel *channel, UA_UInt32 requestId,
 
 
     /* No chunkentry on the channel, create one */
     /* No chunkentry on the channel, create one */
     if(!ch) {
     if(!ch) {
-        ch = (struct ChunkEntry *) UA_malloc(sizeof(struct ChunkEntry));
+        ch = (struct ChunkEntry *)UA_malloc(sizeof(struct ChunkEntry));
         if(!ch)
         if(!ch)
             return UA_STATUSCODE_BADOUTOFMEMORY;
             return UA_STATUSCODE_BADOUTOFMEMORY;
         ch->requestId = requestId;
         ch->requestId = requestId;
@@ -769,7 +781,7 @@ decryptChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cry
         if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
         if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
            (messageType == UA_MESSAGETYPE_OPN &&
            (messageType == UA_MESSAGETYPE_OPN &&
             channel->securityMode > UA_MESSAGESECURITYMODE_NONE)) {
             channel->securityMode > UA_MESSAGESECURITYMODE_NONE)) {
-            paddingSize = (size_t) chunk->data[chunkSizeAfterDecryption - sigsize - 1];
+            paddingSize = (size_t)chunk->data[chunkSizeAfterDecryption - sigsize - 1];
 
 
             size_t keyLength = cryptoModule->getRemoteEncryptionKeyLength(securityPolicy, channel->channelContext);
             size_t keyLength = cryptoModule->getRemoteEncryptionKeyLength(securityPolicy, channel->channelContext);
             if(keyLength > 2048) {
             if(keyLength > 2048) {
@@ -967,8 +979,7 @@ UA_SecureChannel_processChunk(UA_SecureChannel *channel, UA_ByteString *chunk,
         sequenceNumberCallback = processSequenceNumberAsym;
         sequenceNumberCallback = processSequenceNumberAsym;
         break;
         break;
     }
     }
-    default:
-        return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
+    default:return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
     }
     }
 
 
     /* Decrypt message */
     /* Decrypt message */

+ 8 - 0
src/ua_types_encoding_binary.c

@@ -1324,8 +1324,16 @@ DECODE_BINARY(DiagnosticInfo) {
             UA_calloc(1, sizeof(UA_DiagnosticInfo));
             UA_calloc(1, sizeof(UA_DiagnosticInfo));
         if(!dst->innerDiagnosticInfo)
         if(!dst->innerDiagnosticInfo)
             return UA_STATUSCODE_BADOUTOFMEMORY;
             return UA_STATUSCODE_BADOUTOFMEMORY;
+
+        /* Check the recursion limit */
+        if(ctx->depth > UA_ENCODING_MAX_RECURSION)
+            return UA_STATUSCODE_BADENCODINGERROR;
+        ctx->depth++;
+
         dst->hasInnerDiagnosticInfo = true;
         dst->hasInnerDiagnosticInfo = true;
         ret |= DECODE_DIRECT(dst->innerDiagnosticInfo, DiagnosticInfo);
         ret |= DECODE_DIRECT(dst->innerDiagnosticInfo, DiagnosticInfo);
+
+        ctx->depth--;
     }
     }
     return ret;
     return ret;
 }
 }

+ 43 - 1
src/ua_util.h

@@ -107,7 +107,7 @@ UA_atomic_cmpxchg(void * volatile * addr, void *expected, void *newptr) {
 }
 }
 
 
 static UA_INLINE uint32_t
 static UA_INLINE uint32_t
-UA_atomic_add(volatile uint32_t *addr, uint32_t increase) {
+UA_atomic_addUInt32(volatile uint32_t *addr, uint32_t increase) {
 #ifndef UA_ENABLE_MULTITHREADING
 #ifndef UA_ENABLE_MULTITHREADING
     *addr += increase;
     *addr += increase;
     return *addr;
     return *addr;
@@ -120,6 +120,48 @@ UA_atomic_add(volatile uint32_t *addr, uint32_t increase) {
 #endif
 #endif
 }
 }
 
 
+static UA_INLINE size_t
+UA_atomic_addSize(volatile size_t *addr, size_t increase) {
+#ifndef UA_ENABLE_MULTITHREADING
+    *addr += increase;
+    return *addr;
+#else
+# ifdef _MSC_VER /* Visual Studio */
+    return _InterlockedExchangeAdd(addr, increase) + increase;
+# else /* GCC/Clang */
+    return __sync_add_and_fetch(addr, increase);
+# endif
+#endif
+}
+
+static UA_INLINE uint32_t
+UA_atomic_subUInt32(volatile uint32_t *addr, uint32_t decrease) {
+#ifndef UA_ENABLE_MULTITHREADING
+    *addr -= decrease;
+    return *addr;
+#else
+# ifdef _MSC_VER /* Visual Studio */
+    return _InterlockedExchangeSub(addr, decrease) - decrease;
+# else /* GCC/Clang */
+    return __sync_sub_and_fetch(addr, decrease);
+# endif
+#endif
+}
+
+static UA_INLINE size_t
+UA_atomic_subSize(volatile size_t *addr, size_t decrease) {
+#ifndef UA_ENABLE_MULTITHREADING
+    *addr -= decrease;
+    return *addr;
+#else
+# ifdef _MSC_VER /* Visual Studio */
+    return _InterlockedExchangeSub(addr, decrease) - decrease;
+# else /* GCC/Clang */
+    return __sync_sub_and_fetch(addr, decrease);
+# endif
+#endif
+}
+
 /* Utility Functions
 /* Utility Functions
  * ----------------- */
  * ----------------- */
 
 

+ 34 - 0
tests/client/check_client.c

@@ -113,6 +113,39 @@ START_TEST(Client_endpoints) {
 }
 }
 END_TEST
 END_TEST
 
 
+START_TEST(Client_endpoints_empty) {
+        /* Issue a getEndpoints call with empty endpointUrl.
+         * Using UA_Client_getEndpoints automatically passes the client->endpointUrl as requested endpointUrl.
+         * The spec says:
+         * The Server should return a suitable default URL if it does not recognize the HostName in the URL.
+         *
+         * See https://github.com/open62541/open62541/issues/775
+         */
+    UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+
+    UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
+    ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_GetEndpointsRequest request;
+    UA_GetEndpointsRequest_init(&request);
+    request.requestHeader.timestamp = UA_DateTime_now();
+    request.requestHeader.timeoutHint = 10000;
+
+    UA_GetEndpointsResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);
+
+    ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
+
+    ck_assert_msg(response.endpointsSize > 0);
+
+    UA_GetEndpointsResponse_deleteMembers(&response);
+    UA_GetEndpointsRequest_deleteMembers(&request);
+
+    UA_Client_delete(client);
+}
+END_TEST
+
 START_TEST(Client_read) {
 START_TEST(Client_read) {
     UA_Client *client = UA_Client_new(UA_ClientConfig_default);
     UA_Client *client = UA_Client_new(UA_ClientConfig_default);
     UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
     UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
@@ -277,6 +310,7 @@ static Suite* testSuite_Client(void) {
     tcase_add_test(tc_client, Client_connect);
     tcase_add_test(tc_client, Client_connect);
     tcase_add_test(tc_client, Client_connect_username);
     tcase_add_test(tc_client, Client_connect_username);
     tcase_add_test(tc_client, Client_endpoints);
     tcase_add_test(tc_client, Client_endpoints);
+    tcase_add_test(tc_client, Client_endpoints_empty);
     tcase_add_test(tc_client, Client_read);
     tcase_add_test(tc_client, Client_read);
     tcase_add_test(tc_client, Client_delete_without_connect);
     tcase_add_test(tc_client, Client_delete_without_connect);
     suite_add_tcase(s,tc_client);
     suite_add_tcase(s,tc_client);

+ 1 - 1
tests/client/check_client_subscriptions.c

@@ -53,7 +53,7 @@ static void teardown(void) {
 UA_Boolean notificationReceived;
 UA_Boolean notificationReceived;
 UA_UInt32 countNotificationReceived = 0;
 UA_UInt32 countNotificationReceived = 0;
 
 
-static void monitoredItemHandler(UA_UInt32 monId, UA_DataValue *value, void *context) {
+static void monitoredItemHandler(UA_Client *client, UA_UInt32 monId, UA_DataValue *value, void *context) {
     notificationReceived = true;
     notificationReceived = true;
     countNotificationReceived++;
     countNotificationReceived++;
 }
 }

+ 1 - 1
tests/fuzz/corpus_generator.c

@@ -360,7 +360,7 @@ translateBrowsePathsToNodeIdsRequest(UA_Client *client) {
 
 
 
 
 static void
 static void
-monitoredItemHandler(UA_UInt32 monId, UA_DataValue *value, void *context) {
+monitoredItemHandler(UA_Client *client, UA_UInt32 monId, UA_DataValue *value, void *context) {
 
 
 }
 }
 
 

+ 5 - 3
tests/testing-plugins/testing_policy.c

@@ -4,8 +4,9 @@
 
 
 #ifndef __clang_analyzer__
 #ifndef __clang_analyzer__
 
 
-#include <ua_types.h>
-#include <ua_plugin_securitypolicy.h>
+#include "ua_types.h"
+#include "ua_plugin_securitypolicy.h"
+#include "ua_log_stdout.h"
 #include "ua_types_generated_handling.h"
 #include "ua_types_generated_handling.h"
 #include "testing_policy.h"
 #include "testing_policy.h"
 #include "check.h"
 #include "check.h"
@@ -339,7 +340,8 @@ TestingPolicy(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
     funcsCalled = fCalled;
     funcsCalled = fCalled;
     policy->policyContext = (void *) funcsCalled;
     policy->policyContext = (void *) funcsCalled;
     policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Testing");
     policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Testing");
-    policy->logger = NULL;
+    policy->logger = UA_Log_Stdout;
+    policy->certificateVerification = NULL;
     UA_ByteString_copy(&localCertificate, &policy->localCertificate);
     UA_ByteString_copy(&localCertificate, &policy->localCertificate);
 
 
     policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_testing;
     policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_testing;

+ 1 - 1
tools/amalgamate.py

@@ -76,7 +76,7 @@ if is_c:
 else:
 else:
     file.write(u'''#ifndef %s
     file.write(u'''#ifndef %s
 #define %s
 #define %s
-''' % (outname.upper() + u"_H_", outname.upper() + u"_H_") )
+''' % (outname.upper() + u"_H_", outname.upper() + u"_H_"))
 
 
 for fname in args.inputs:
 for fname in args.inputs:
     with io.open(fname, encoding='utf8', errors='replace') as infile:
     with io.open(fname, encoding='utf8', errors='replace') as infile:

+ 56 - 0
tools/clang-format_precommit_hook

@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# This pre-commit hook checks if any versions of clang-format
+# are installed, and if so, uses the installed version to format
+# the staged changes.
+#
+# To install, copy this script to `.git/hooks/pre-commit`:
+# ln -s ../../tools/clang-format_precommit_hook .git/hooks/pre-commit
+# and make sure that `clang-format` is installed on your system
+
+maj_min=1
+maj_max=3
+
+base=clang-format
+format=""
+
+# Redirect output to stderr.
+exec 1>&2
+
+ # check if clang-format is installed
+type "$base" >/dev/null 2>&1 && format="$base"
+
+# if not, check all possible versions
+# (i.e. clang-format-<$maj_min-$maj_max>-<0-9>)
+if [ -z "$format" ]
+then
+    for j in `seq $maj_max -1 $maj_min`
+    do
+        for i in `seq 0 9`
+        do
+            type "$base-$j.$i" >/dev/null 2>&1 && format="$base-$j.$i" && break
+        done
+        [ -z "$format" ] || break
+    done
+fi
+
+# no versions of clang-format are installed
+if [ -z "$format" ]
+then
+    echo "$base is not installed. Pre-commit hook will not be executed."
+    exit 0
+fi
+
+if git rev-parse --verify HEAD >/dev/null 2>&1
+then
+	against=HEAD
+else
+	# Initial commit: diff against an empty tree object
+	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+# do the formatting
+for file in `git diff-index --cached --name-only $against`
+do
+    "$format" -i "$file"
+done

+ 15 - 4
tools/generate_datatypes.py

@@ -108,7 +108,10 @@ class Type(object):
             return "#define %s_members NULL" % (self.name)
             return "#define %s_members NULL" % (self.name)
         members = "static UA_DataTypeMember %s_members[%s] = {" % (self.name, len(self.members))
         members = "static UA_DataTypeMember %s_members[%s] = {" % (self.name, len(self.members))
         before = None
         before = None
+        i = 0
+        size = len(self.members)
         for index, member in enumerate(self.members):
         for index, member in enumerate(self.members):
+            i += 1
             m = "\n{\n    UA_TYPENAME(\"%s\") /* .memberName */\n" % member.name
             m = "\n{\n    UA_TYPENAME(\"%s\") /* .memberName */\n" % member.name
             m += "    %s_%s, /* .memberTypeIndex */\n" % (member.memberType.outname.upper(), member.memberType.name.upper())
             m += "    %s_%s, /* .memberTypeIndex */\n" % (member.memberType.outname.upper(), member.memberType.name.upper())
             m += "    "
             m += "    "
@@ -126,7 +129,9 @@ class Type(object):
                     m += " - sizeof(UA_%s)," % before.memberType.name
                     m += " - sizeof(UA_%s)," % before.memberType.name
             m += " /* .padding */\n"
             m += " /* .padding */\n"
             m += "    %s, /* .namespaceZero */\n" % member.memberType.ns0
             m += "    %s, /* .namespaceZero */\n" % member.memberType.ns0
-            m += ("    true" if member.isArray else "    false") + " /* .isArray */\n},"
+            m += ("    true" if member.isArray else "    false") + " /* .isArray */\n}"
+            if i != size:
+                m += ","
             members += m
             members += m
             before = member
             before = member
         return members + "};"
         return members + "};"
@@ -501,7 +506,9 @@ printh("extern UA_EXPORT const UA_DataType " + outname.upper() + "[" + outname.u
 
 
 i = 0
 i = 0
 for t in filtered_types:
 for t in filtered_types:
-    printh("\n/**\n * " +  t.name)
+    if i != 0:
+        printh("\n")
+    printh("/**\n * " +  t.name)
     printh(" * " + "^" * len(t.name))
     printh(" * " + "^" * len(t.name))
     if t.description == "":
     if t.description == "":
         printh(" */")
         printh(" */")
@@ -512,9 +519,12 @@ for t in filtered_types:
     printh("#define " + outname.upper() + "_" + t.name.upper() + " " + str(i))
     printh("#define " + outname.upper() + "_" + t.name.upper() + " " + str(i))
     i += 1
     i += 1
 
 
+i = 0
 # Generate alias for opaque types
 # Generate alias for opaque types
 for t in filtered_opaque_types:
 for t in filtered_opaque_types:
-    printh("\n/**\n * " +  t.name)
+    if i != 0:
+        printh("\n")
+    printh("/**\n * " +  t.name)
     printh(" * " + "^" * len(t.name))
     printh(" * " + "^" * len(t.name))
     if t.description == "":
     if t.description == "":
         printh(" */")
         printh(" */")
@@ -523,6 +533,7 @@ for t in filtered_opaque_types:
     if type(t) != BuiltinType:
     if type(t) != BuiltinType:
         printh(t.typedef_h() + "\n")
         printh(t.typedef_h() + "\n")
     printh("#define " + outname.upper() + "_" + t.name.upper() + " " + outname.upper() + "_" + get_base_type_for_opaque(t.name)['name'].upper())
     printh("#define " + outname.upper() + "_" + t.name.upper() + " " + outname.upper() + "_" + get_base_type_for_opaque(t.name)['name'].upper())
+    i += 1
 
 
 printh('''
 printh('''
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -585,7 +596,7 @@ for t in filtered_types:
 
 
 printc("const UA_DataType %s[%s_COUNT] = {" % (outname.upper(), outname.upper()))
 printc("const UA_DataType %s[%s_COUNT] = {" % (outname.upper(), outname.upper()))
 for t in filtered_types:
 for t in filtered_types:
-    printc("")
+#    printc("")
     printc("/* " + t.name + " */")
     printc("/* " + t.name + " */")
     printc(t.datatype_c() + ",")
     printc(t.datatype_c() + ",")
 printc("};\n")
 printc("};\n")

+ 3 - 3
tools/generate_statuscode_descriptions.py

@@ -58,13 +58,13 @@ static const UA_StatusCodeName statusCodeDescriptions[%i] = {
 ''' % (count, count))
 ''' % (count, count))
 
 
 for row in rows:
 for row in rows:
-    printc(u"    {UA_STATUSCODE_%s, \"%s\",}," % (row[0].upper(), row[0]))
+    printc(u"    {UA_STATUSCODE_%s, \"%s\"}," % (row[0].upper(), row[0]))
 printc(u'''    {0xffffffff, "Unknown StatusCode"}
 printc(u'''    {0xffffffff, "Unknown StatusCode"}
 };
 };
 
 
 const char * UA_StatusCode_name(UA_StatusCode code) {
 const char * UA_StatusCode_name(UA_StatusCode code) {
-    for(size_t i = 0; i < statusCodeDescriptionsSize; ++i) {
-        if(statusCodeDescriptions[i].code == code)
+    for (size_t i = 0; i < statusCodeDescriptionsSize; ++i) {
+        if (statusCodeDescriptions[i].code == code)
             return statusCodeDescriptions[i].name;
             return statusCodeDescriptions[i].name;
     }
     }
     return statusCodeDescriptions[statusCodeDescriptionsSize-1].name;
     return statusCodeDescriptions[statusCodeDescriptionsSize-1].name;

+ 3 - 4
tools/nodeset_compiler/backend_open62541.py

@@ -226,7 +226,7 @@ extern UA_StatusCode %s(UA_Server *server);
         # Print node
         # Print node
         if not node.hidden:
         if not node.hidden:
             writec("\n/* " + str(node.displayName) + " - " + str(node.id) + " */")
             writec("\n/* " + str(node.displayName) + " - " + str(node.id) + " */")
-            writec("\nstatic UA_StatusCode function_" + outfilebase + "_" + str(functionNumber) + "_begin(UA_Server *server, UA_UInt16* ns){\n")
+            writec("\nstatic UA_StatusCode function_" + outfilebase + "_" + str(functionNumber) + "_begin(UA_Server *server, UA_UInt16* ns) {\n")
             code = generateNodeCode_begin(node, nodeset, max_string_length)
             code = generateNodeCode_begin(node, nodeset, max_string_length)
             if code is None:
             if code is None:
                 writec("/* Ignored. No parent */")
                 writec("/* Ignored. No parent */")
@@ -241,7 +241,7 @@ extern UA_StatusCode %s(UA_Server *server);
             
             
         writec("return retVal;\n}")
         writec("return retVal;\n}")
 
 
-        writec("\nstatic UA_StatusCode function_" + outfilebase + "_" + str(functionNumber) + "_finish(UA_Server *server, UA_UInt16* ns){\n")
+        writec("\nstatic UA_StatusCode function_" + outfilebase + "_" + str(functionNumber) + "_finish(UA_Server *server, UA_UInt16* ns) {\n")
         code = generateNodeCode_finish(node, generate_ns0, parentrefs)
         code = generateNodeCode_finish(node, generate_ns0, parentrefs)
         writec("return " + code + "\n}\n")
         writec("return " + code + "\n}\n")
 
 
@@ -249,8 +249,7 @@ extern UA_StatusCode %s(UA_Server *server);
     
     
     
     
     writec("""
     writec("""
-UA_StatusCode %s(UA_Server *server) {  // NOLINT
-
+UA_StatusCode %s(UA_Server *server) {
 UA_StatusCode retVal = UA_STATUSCODE_GOOD;""" % (outfilebase))
 UA_StatusCode retVal = UA_STATUSCODE_GOOD;""" % (outfilebase))
     # Generate namespaces (don't worry about duplicates)
     # Generate namespaces (don't worry about duplicates)
     writec("/* Use namespace ids generated by the server */")
     writec("/* Use namespace ids generated by the server */")

+ 3 - 3
tools/nodeset_compiler/backend_open62541_datatypes.py

@@ -52,11 +52,11 @@ def generateQualifiedNameCode(value, alloc=False, max_string_length=0):
 
 
 def generateNodeIdCode(value):
 def generateNodeIdCode(value):
     if not value:
     if not value:
-        return "UA_NODEID_NUMERIC(0,0)"
+        return "UA_NODEID_NUMERIC(0, 0)"
     if value.i != None:
     if value.i != None:
-        return "UA_NODEID_NUMERIC(ns[%s],%s)" % (value.ns, value.i)
+        return "UA_NODEID_NUMERIC(ns[%s], %s)" % (value.ns, value.i)
     elif value.s != None:
     elif value.s != None:
-        return "UA_NODEID_STRING(ns[%s],%s)" % (value.ns, value.s.replace('"', r'\"'))
+        return "UA_NODEID_STRING(ns[%s], %s)" % (value.ns, value.s.replace('"', r'\"'))
     raise Exception(str(value) + " no NodeID generation for bytestring and guid..")
     raise Exception(str(value) + " no NodeID generation for bytestring and guid..")
 
 
 def generateExpandedNodeIdCode(value):
 def generateExpandedNodeIdCode(value):

+ 6 - 6
tools/nodeset_compiler/backend_open62541_nodes.py

@@ -250,7 +250,7 @@ def generateExtensionObjectSubtypeCode(node, parent, nodeset, recursionDepth=0,
         instanceName + "->content.encoded.typeId = UA_NODEID_NUMERIC(" + str(binaryEncodingId.ns) + ", " +
         instanceName + "->content.encoded.typeId = UA_NODEID_NUMERIC(" + str(binaryEncodingId.ns) + ", " +
         str(binaryEncodingId.i) + ");")
         str(binaryEncodingId.i) + ");")
     code.append(
     code.append(
-        "if(UA_ByteString_allocBuffer(&" + instanceName + "->content.encoded.body, 65000) != UA_STATUSCODE_GOOD) {}")
+        "UA_ByteString_allocBuffer(&" + instanceName + "->content.encoded.body, 65000);")
 
 
     # Encode each value as a bytestring separately.
     # Encode each value as a bytestring separately.
     code.append("UA_Byte *pos" + instanceName + " = " + instanceName + "->content.encoded.body.data;")
     code.append("UA_Byte *pos" + instanceName + " = " + instanceName + "->content.encoded.body.data;")
@@ -280,7 +280,7 @@ def generateExtensionObjectSubtypeCode(node, parent, nodeset, recursionDepth=0,
     code.append("size_t " + instanceName + "_encOffset = (uintptr_t)(" +
     code.append("size_t " + instanceName + "_encOffset = (uintptr_t)(" +
                 "pos" + instanceName + "-" + instanceName + "->content.encoded.body.data);")
                 "pos" + instanceName + "-" + instanceName + "->content.encoded.body.data);")
     code.append(instanceName + "->content.encoded.body.length = " + instanceName + "_encOffset;")
     code.append(instanceName + "->content.encoded.body.length = " + instanceName + "_encOffset;")
-    code.append("UA_Byte *" + instanceName + "_newBody = (UA_Byte *) UA_malloc(" + instanceName + "_encOffset );")
+    code.append("UA_Byte *" + instanceName + "_newBody = (UA_Byte *) UA_malloc(" + instanceName + "_encOffset);")
     code.append("memcpy(" + instanceName + "_newBody, " + instanceName + "->content.encoded.body.data, " +
     code.append("memcpy(" + instanceName + "_newBody, " + instanceName + "->content.encoded.body.data, " +
                 instanceName + "_encOffset);")
                 instanceName + "_encOffset);")
     code.append("UA_Byte *" + instanceName + "_oldBody = " + instanceName + "->content.encoded.body.data;")
     code.append("UA_Byte *" + instanceName + "_oldBody = " + instanceName + "->content.encoded.body.data;")
@@ -306,7 +306,7 @@ def generateValueCodeDummy(dataTypeNode, parentNode, nodeset, bootstrapping=True
         code.append(typeStr + " *" + valueName + " = (" + typeStr + "*) UA_alloca(" + typeArr + ".memSize * " + str(parentNode.valueRank) + ");")
         code.append(typeStr + " *" + valueName + " = (" + typeStr + "*) UA_alloca(" + typeArr + ".memSize * " + str(parentNode.valueRank) + ");")
         for i in range(0, parentNode.valueRank):
         for i in range(0, parentNode.valueRank):
             code.append("UA_init(&" + valueName + "[" + str(i) + "], &" + typeArr + ");")
             code.append("UA_init(&" + valueName + "[" + str(i) + "], &" + typeArr + ");")
-            code.append("UA_Variant_setArray( &attr.value, " + valueName + ", (UA_Int32) " +
+            code.append("UA_Variant_setArray(&attr.value, " + valueName + ", (UA_Int32) " +
                         str(parentNode.valueRank) + ", &" + typeArr + ");")
                         str(parentNode.valueRank) + ", &" + typeArr + ");")
     else:
     else:
         code.append("void *" + valueName + " = UA_alloca(" + typeArr + ".memSize);")
         code.append("void *" + valueName + " = UA_alloca(" + typeArr + ".memSize);")
@@ -376,7 +376,7 @@ def generateValueCode(node, parentNode, nodeset, bootstrapping=True, max_string_
                     instanceName = generateNodeValueInstanceName(v, parentNode, 0, idx)
                     instanceName = generateNodeValueInstanceName(v, parentNode, 0, idx)
                     code.append(
                     code.append(
                         valueName + "[" + str(idx) + "] = " + generateNodeValueCode(v, instanceName, max_string_length=max_string_length) + ";")
                         valueName + "[" + str(idx) + "] = " + generateNodeValueCode(v, instanceName, max_string_length=max_string_length) + ";")
-            code.append("UA_Variant_setArray( &attr.value, &" + valueName +
+            code.append("UA_Variant_setArray(&attr.value, &" + valueName +
                         ", (UA_Int32) " + str(len(node.value)) + ", " +
                         ", (UA_Int32) " + str(len(node.value)) + ", " +
                         getTypesArrayForValue(nodeset, node.value[0]) + ");")
                         getTypesArrayForValue(nodeset, node.value[0]) + ");")
     else:
     else:
@@ -398,7 +398,7 @@ def generateValueCode(node, parentNode, nodeset, bootstrapping=True, max_string_
                 code.append("UA_" + node.value[0].__class__.__name__ + " *" + valueName + " = " +
                 code.append("UA_" + node.value[0].__class__.__name__ + " *" + valueName + " = " +
                             generateNodeValueCode(node.value[0], instanceName, max_string_length=max_string_length) + ";")
                             generateNodeValueCode(node.value[0], instanceName, max_string_length=max_string_length) + ";")
                 code.append(
                 code.append(
-                    "UA_Variant_setScalar( &attr.value, " + valueName + ", " +
+                    "UA_Variant_setScalar(&attr.value, " + valueName + ", " +
                     getTypesArrayForValue(nodeset, node.value[0]) + ");")
                     getTypesArrayForValue(nodeset, node.value[0]) + ");")
 
 
                 # FIXME: There is no membership definition for extensionObjects generated in this function.
                 # FIXME: There is no membership definition for extensionObjects generated in this function.
@@ -408,7 +408,7 @@ def generateValueCode(node, parentNode, nodeset, bootstrapping=True, max_string_
                     0].__class__.__name__ + "_new();")
                     0].__class__.__name__ + "_new();")
                 code.append("*" + valueName + " = " + generateNodeValueCode(node.value[0], instanceName, asIndirect=True, max_string_length=max_string_length) + ";")
                 code.append("*" + valueName + " = " + generateNodeValueCode(node.value[0], instanceName, asIndirect=True, max_string_length=max_string_length) + ";")
                 code.append(
                 code.append(
-                        "UA_Variant_setScalar( &attr.value, " + valueName + ", " +
+                        "UA_Variant_setScalar(&attr.value, " + valueName + ", " +
                         getTypesArrayForValue(nodeset, node.value[0]) + ");")
                         getTypesArrayForValue(nodeset, node.value[0]) + ");")
                 codeCleanup.append("UA_{0}_delete({1});".format(
                 codeCleanup.append("UA_{0}_delete({1});".format(
                     node.value[0].__class__.__name__, valueName))
                     node.value[0].__class__.__name__, valueName))

+ 1 - 1
tools/travis/travis_linux_before_install.sh

@@ -32,13 +32,13 @@ if [ -z ${DOCKER+x} ]; then
 
 
 	sudo add-apt-repository -y ppa:lttng/ppa
 	sudo add-apt-repository -y ppa:lttng/ppa
 	sudo apt-get update -qq
 	sudo apt-get update -qq
-	sudo apt-get install -y liburcu4 liburcu-dev
 	echo -en 'travis_fold:end:script.before_install.external\\r'
 	echo -en 'travis_fold:end:script.before_install.external\\r'
 
 
 	echo "=== Installing python packages ===" && echo -en 'travis_fold:start:before_install.python\\r'
 	echo "=== Installing python packages ===" && echo -en 'travis_fold:start:before_install.python\\r'
 	pip install --user cpp-coveralls
 	pip install --user cpp-coveralls
 	pip install --user sphinx
 	pip install --user sphinx
 	pip install --user sphinx_rtd_theme
 	pip install --user sphinx_rtd_theme
+	pip install --user cpplint
 	echo -en 'travis_fold:end:script.before_install.python\\r'
 	echo -en 'travis_fold:end:script.before_install.python\\r'
 
 
 	echo "=== Installed versions are ===" && echo -en 'travis_fold:start:before_install.versions\\r'
 	echo "=== Installed versions are ===" && echo -en 'travis_fold:start:before_install.versions\\r'

+ 10 - 0
tools/travis/travis_linux_script.sh

@@ -11,6 +11,16 @@ if ! [ -z ${DOCKER+x} ]; then
     exit 0
     exit 0
 fi
 fi
 
 
+# Cpplint checking
+if ! [ -z ${LINT+x} ]; then
+	mkdir -p build
+	cd build
+	cmake ..
+	make cpplint
+	if [ $? -ne 0 ] ; then exit 1 ; fi
+    exit 0
+fi
+
 # Fuzzer build test
 # Fuzzer build test
 if ! [ -z ${FUZZER+x} ]; then
 if ! [ -z ${FUZZER+x} ]; then
     # Test the corpus generator and use new corpus for fuzz test
     # Test the corpus generator and use new corpus for fuzz test

+ 0 - 1
tools/travis/travis_osx_before_install.sh

@@ -2,7 +2,6 @@
 set -ev
 set -ev
 
 
 brew install check
 brew install check
-brew install userspace-rcu
 brew install valgrind
 brew install valgrind
 brew install graphviz
 brew install graphviz
 brew install python
 brew install python