Prechádzať zdrojové kódy

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

Thomas Bender 6 rokov pred
rodič
commit
de16606199
50 zmenil súbory, kde vykonal 460 pridanie a 165 odobranie
  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
       compiler: clang
       env: FUZZER=true
+    #- os: linux
+    #  compiler: gcc
+    #  env: LINT=true
     # - os: osx
     #   compiler: clang
     #   # 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
 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>
 
  * 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 stdc++)
   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"))
       list(APPEND open62541_LIBRARIES rt)
     endif()
@@ -199,9 +202,6 @@ else()
         list(APPEND open62541_LIBRARIES iphlpapi)
     endif()
 endif()
-if(UA_ENABLE_MULTITHREADING)
-  list(APPEND open62541_LIBRARIES urcu-cds urcu-bp urcu-common)
-endif(UA_ENABLE_MULTITHREADING)
 
 #####################
 # Compiler Settings #
@@ -717,6 +717,18 @@ add_custom_target(lint ${CLANG_TIDY_PROGRAM}
                   COMMENT "Run clang-tidy on the library")
 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           #
 ##########################

+ 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
    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 liburcu-dev # for multithreading
    sudo apt-get install check # for unit tests
    sudo apt-get install python-sphinx graphviz # for documentation generation
    sudo apt-get install python-sphinx-rtd-theme # documentation style

+ 1 - 1
examples/client.c

@@ -6,7 +6,7 @@
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 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");
 }
 #endif

+ 1 - 1
examples/client_subscription_loop.c

@@ -43,7 +43,7 @@ static void stopHandler(int sign) {
 }
 
 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!");
     if(UA_Variant_hasScalarType(&value->value, &UA_TYPES[UA_TYPES_DATETIME])) {
         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
 
 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) {
     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 */
 /* 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_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
  * 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 UA_Variant *eventFields,
                                                   void *context);

+ 2 - 0
include/ua_plugin_securitypolicy.h

@@ -17,6 +17,7 @@ extern "C" {
 #include "ua_types.h"
 #include "ua_types_generated.h"
 #include "ua_plugin_log.h"
+#include "ua_plugin_pki.h"
 
 extern const UA_ByteString UA_SECURITY_POLICY_NONE_URI;
 
@@ -295,6 +296,7 @@ struct UA_SecurityPolicy {
     UA_SecurityPolicyAsymmetricModule asymmetricModule;
     UA_SecurityPolicySymmetricModule symmetricModule;
     UA_SecurityPolicyChannelModule channelModule;
+    UA_CertificateVerification *certificateVerification;
 
     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) {
     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.securityPolicyUri =
         UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
@@ -127,7 +127,7 @@ createSecurityPolicyBasic128Rsa15Endpoint(UA_ServerConfig *const conf,
     UA_EndpointDescription_init(&endpoint->endpointDescription);
 
     UA_StatusCode retval =
-        UA_SecurityPolicy_Basic128Rsa15(&endpoint->securityPolicy, localCertificate,
+        UA_SecurityPolicy_Basic128Rsa15(&endpoint->securityPolicy, &conf->certificateVerification, localCertificate,
                                         localPrivateKey, conf->logger);
     if(retval != UA_STATUSCODE_GOOD) {
         endpoint->securityPolicy.deleteMembers(&endpoint->securityPolicy);

+ 0 - 4
plugins/ua_network_udp.c

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

+ 1 - 0
plugins/ua_pki_certificate.c

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

+ 20 - 17
plugins/ua_securitypolicy_basic128rsa15.c

@@ -13,6 +13,7 @@
 #include <mbedtls/entropy.h>
 #include <mbedtls/entropy_poll.h>
 #include <mbedtls/error.h>
+#include <ua_plugin_pki.h>
 
 #include "ua_securitypolicy_basic128rsa15.h"
 #include "ua_types.h"
@@ -271,7 +272,7 @@ asymmetricModule_compareCertificateThumbprint_sp_basic128rsa15(const UA_Security
     if(securityPolicy == NULL || certificateThumbprint == NULL)
         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))
         return UA_STATUSCODE_BADCERTIFICATEINVALID;
 
@@ -306,7 +307,7 @@ sym_verify_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
     }
 
     Basic128Rsa15_PolicyContext *pc =
-        (Basic128Rsa15_PolicyContext*)securityPolicy->policyContext;
+        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
 
     unsigned char mac[UA_SHA1_LENGTH];
     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) {
         UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                      "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;
     }
 
@@ -393,7 +394,7 @@ sym_decrypt_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
         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;
     int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
     UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADINTERNALERROR);
@@ -425,7 +426,7 @@ sym_generateKey_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
         return UA_STATUSCODE_BADINTERNALERROR;
 
     Basic128Rsa15_PolicyContext *pc =
-        (Basic128Rsa15_PolicyContext*)securityPolicy->policyContext;
+        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
 
     size_t hashLen = 0;
     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;
 
     Basic128Rsa15_PolicyContext *data =
-        (Basic128Rsa15_PolicyContext *) securityPolicy->policyContext;
+        (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
 
     int mbedErr = mbedtls_ctr_drbg_random(&data->drbgContext, out->data, out->length);
     UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADUNEXPECTEDERROR);
@@ -526,7 +527,7 @@ parseRemoteCertificate_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
 
     /* Parse the certificate */
     int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
-                                          remoteCertificate->length);
+                                         remoteCertificate->length);
     UA_MBEDTLS_ERRORHANDLING_RETURN(UA_STATUSCODE_BADSECURITYCHECKSFAILED);
 
     /* Check the key length */
@@ -565,10 +566,10 @@ channelContext_newContext_sp_basic128rsa15(const UA_SecurityPolicy *securityPoli
     if(*pp_contextData == NULL)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
-    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext*)*pp_contextData;
+    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)*pp_contextData;
 
     /* 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->localSymEncryptingKey);
@@ -681,7 +682,7 @@ static size_t
 channelContext_getRemoteAsymEncryptionBufferLengthOverhead_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc,
                                                                             size_t maxEncryptionLength) {
     const size_t maxNumberOfBlocks = maxEncryptionLength /
-        channelContext_getRemoteAsymPlainTextBlockSize_sp_basic128rsa15(cc);
+                                     channelContext_getRemoteAsymPlainTextBlockSize_sp_basic128rsa15(cc);
     return maxNumberOfBlocks * UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
 }
 
@@ -696,7 +697,7 @@ deleteMembers_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy) {
     UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
 
     /* delete all allocated members in the context */
-    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext*)
+    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
         securityPolicy->policyContext;
 
     mbedtls_ctr_drbg_free(&pc->drbgContext);
@@ -721,7 +722,7 @@ policyContext_newContext_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
 
     Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
         UA_malloc(sizeof(Basic128Rsa15_PolicyContext));
-    securityPolicy->policyContext = (void*)pc;
+    securityPolicy->policyContext = (void *)pc;
     if(!pc) {
         retval = UA_STATUSCODE_BADOUTOFMEMORY;
         goto error;
@@ -788,8 +789,9 @@ error:
 }
 
 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));
     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 */
     UA_StatusCode retval =
-        UA_ByteString_allocBuffer(&policy->localCertificate, localCertificate.length+1);
+        UA_ByteString_allocBuffer(&policy->localCertificate, localCertificate.length + 1);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     memcpy(policy->localCertificate.data, localCertificate.data, localCertificate.length);
     policy->localCertificate.data[localCertificate.length] = '\0';
     policy->localCertificate.length--;
+    policy->certificateVerification = certificateVerification;
 
     /* AsymmetricModule */
     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;
     asymmetricModule->cryptoModule.decrypt =
         (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.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;
     symmetricModule->cryptoModule.decrypt =
         (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.getRemoteEncryptionKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15;
 

+ 1 - 0
plugins/ua_securitypolicy_basic128rsa15.h

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

+ 4 - 2
plugins/ua_securitypolicy_none.c

@@ -121,13 +121,15 @@ policy_deletemembers_none(UA_SecurityPolicy *policy) {
 }
 
 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->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
     policy->logger = logger;
     UA_ByteString_copy(&localCertificate, &policy->localCertificate);
 
+    policy->certificateVerification = certificateVerification;
+
     policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_none;
     policy->asymmetricModule.compareCertificateThumbprint = compareThumbprint_none;
     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"
 
 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
 }

+ 2 - 2
src/client/ua_client.c

@@ -32,7 +32,7 @@ static void
 UA_Client_init(UA_Client* client, UA_ClientConfig config) {
     memset(client, 0, sizeof(UA_Client));
     /* TODO: Select policy according to the endpoint */
-    UA_SecurityPolicy_None(&client->securityPolicy, UA_BYTESTRING_NULL, config.logger);
+    UA_SecurityPolicy_None(&client->securityPolicy, NULL, UA_BYTESTRING_NULL, config.logger);
     client->channel.securityPolicy = &client->securityPolicy;
     client->channel.securityMode = UA_MESSAGESECURITYMODE_NONE;
     client->config = config;
@@ -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_BADCONNECTIONCLOSED)
-                client->state = UA_CLIENTSTATE_DISCONNECTED;
+                setClientState(client, UA_CLIENTSTATE_DISCONNECTED);
             UA_Client_close(client);
             break;
         }

+ 1 - 1
src/client/ua_client_connect.c

@@ -22,7 +22,7 @@
  /********************/
  /* Set client state */
  /********************/
-static void
+void
 setClientState(UA_Client *client, UA_ClientState 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;
                 }
 
-                mon->handler.dataChangeHandler(mon->monitoredItemId, &mitemNot->value, mon->handlerContext);
+                mon->handler.dataChangeHandler(client, mon->monitoredItemId,
+                                               &mitemNot->value, mon->handlerContext);
             }
             continue;
         }
@@ -457,7 +458,7 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
                     continue;
                 }
 
-                mon->handler.eventHandler(mon->monitoredItemId, eventFieldList->eventFieldsSize,
+                mon->handler.eventHandler(client, mon->monitoredItemId, eventFieldList->eventFieldsSize,
                                           eventFieldList->eventFields, mon->handlerContext);
             }
         }

+ 3 - 0
src/client/ua_client_internal.h

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

+ 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
     listEntry->serverOnNetwork.serverName.data = (UA_Byte*)UA_malloc(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)
         server->serverOnNetworkRecordIdLastReset = UA_DateTime_now();
 
@@ -169,7 +169,7 @@ mdns_record_remove(UA_Server *server, const char *record,
     server->serverOnNetworkSize--;
     UA_free(entry);
 #else
-    server->serverOnNetworkSize = uatomic_add_return(&server->serverOnNetworkSize, -1);
+    UA_atomic_subSize(&server->serverOnNetworkSize, 1);
     UA_Server_delayedCallback(server, delayedFree, entry);
 #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 */
     LIST_REMOVE(entry, pointers);
-    UA_atomic_add(&cm->currentChannelCount, (UA_UInt32)-1);
+    UA_atomic_subUInt32(&cm->currentChannelCount, 1);
     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;
 
     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);
     return UA_STATUSCODE_GOOD;
 }

+ 3 - 2
src/server/ua_server.c

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

+ 11 - 8
src/server/ua_server_internal.h

@@ -28,13 +28,17 @@ extern "C" {
 
 #ifdef UA_ENABLE_MULTITHREADING
 
-/* TODO: Don't depend on liburcu */
-#include <urcu.h>
-#include <urcu/lfstack.h>
+#include <pthread.h>
 
 struct UA_Worker;
 typedef struct UA_Worker UA_Worker;
 
+struct UA_WorkerCallback;
+typedef struct UA_WorkerCallback UA_WorkerCallback;
+
+SIMPLEQ_HEAD(UA_DispatchQueue, UA_WorkerCallback);
+typedef struct UA_DispatchQueue UA_DispatchQueue;
+
 #endif /* UA_ENABLE_MULTITHREADING */
 
 #ifdef UA_ENABLE_DISCOVERY
@@ -126,12 +130,11 @@ struct UA_Server {
 
     /* Worker threads */
 #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_DispatchQueue dispatchQueue; /* Dispatch queue for the worker threads */
+    pthread_mutex_t dispatchQueue_accessMutex; /* mutex for access to queue */
     pthread_cond_t dispatchQueue_condition; /* so the workers don't spin if the queue is empty */
-    pthread_mutex_t dispatchQueue_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
 
     /* For bootstrapping, omit some consistency checks, creating a reference to
@@ -276,7 +279,7 @@ compatibleValueRankArrayDimensions(UA_Int32 valueRank, size_t arrayDimensionsSiz
 
 UA_Boolean
 compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
-                   const UA_NodeId *constraintDataType);
+                   const UA_NodeId *constraintDataType, UA_Boolean isValue);
 
 UA_Boolean
 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)];
 };
 
-typedef struct {
-    struct cds_wfcq_node node;
+struct UA_WorkerCallback {
+    SIMPLEQ_ENTRY(UA_WorkerCallback) next;
     UA_ServerCallback callback;
     void *data;
 
     UA_Boolean delayed;         /* Is it a delayed callback? */
     UA_Boolean countersSampled; /* Have the worker counters been sampled? */
     UA_UInt32 workerCounters[]; /* Counter value for each worker */
-} WorkerCallback;
+};
+typedef struct UA_WorkerCallback WorkerCallback;
 
 /* Forward Declaration */
 static void
@@ -69,16 +70,19 @@ workerLoop(UA_Worker *worker) {
     UA_random_seed((uintptr_t)worker);
 
     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) {
             /* 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,
-                              &server->dispatchQueue_mutex);
-            pthread_mutex_unlock(&server->dispatchQueue_mutex);
+                              &server->dispatchQueue_conditionMutex);
+            pthread_mutex_unlock(&server->dispatchQueue_conditionMutex);
             continue;
         }
 
@@ -98,14 +102,14 @@ workerLoop(UA_Worker *worker) {
 
 static void
 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);
         UA_free(dc);
     }
+    pthread_mutex_unlock(&server->dispatchQueue_accessMutex);
 }
 
 #endif
@@ -135,9 +139,9 @@ UA_Server_workerCallback(UA_Server *server, UA_ServerCallback callback,
     dc->callback = callback;
     dc->data = data;
     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 */
     pthread_cond_broadcast(&server->dispatchQueue_condition);
@@ -210,9 +214,9 @@ UA_Server_delayedCallback(UA_Server *server, UA_ServerCallback callback,
     dc->data = data;
     dc->delayed = true;
     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 */
     pthread_cond_broadcast(&server->dispatchQueue_condition);
@@ -229,9 +233,9 @@ processDelayedCallback(UA_Server *server, WorkerCallback *dc) {
         dc->countersSampled = true;
 
         /* 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 */
         pthread_cond_broadcast(&server->dispatchQueue_condition);
@@ -251,9 +255,9 @@ processDelayedCallback(UA_Server *server, WorkerCallback *dc) {
      * TODO: What is the impact of this loop?
      * Can we add a small delay here? */
     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 */
         pthread_cond_broadcast(&server->dispatchQueue_condition);
@@ -301,8 +305,9 @@ UA_Server_run_startup(UA_Server *server) {
 #ifdef UA_ENABLE_MULTITHREADING
     UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
                 "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));
     if(!server->workers)
         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
 compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
-                   const UA_NodeId *constraintDataType) {
+                   const UA_NodeId *constraintDataType, UA_Boolean isValue) {
     /* Do not allow empty datatypes */
     if(UA_NodeId_isNull(dataType))
        return false;
@@ -545,6 +545,10 @@ compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
     if(UA_NodeId_isNull(constraintDataType))
         return true;
 
+    /* Same datatypes */
+    if (UA_NodeId_equal(dataType, constraintDataType))
+        return true;
+
     /* Variant allows any subtype */
     if(UA_NodeId_equal(constraintDataType, &UA_TYPES[UA_TYPES_VARIANT].typeId))
         return true;
@@ -553,22 +557,25 @@ compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
     if(isNodeInTree(&server->config.nodestore, dataType, constraintDataType, &subtypeId, 1))
         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) */
     if(UA_NodeId_equal(dataType, &UA_TYPES[UA_TYPES_INT32].typeId) &&
        isNodeInTree(&server->config.nodestore, constraintDataType, &enumNodeId, &subtypeId, 1))
         return true;
 
+    /* More checks for the data type of real values (variants) */
+    if(isValue) {
+        /* If value is a built-in type: The target data type may be a sub type of
+         * the built-in type. (e.g. UtcTime is sub-type of DateTime and has a
+         * DateTime value). A type is builtin if its NodeId is in Namespace 0 and
+         * has a numeric identifier <= 25 (DiagnosticInfo) */
+        if(dataType->namespaceIndex == 0 &&
+           dataType->identifierType == UA_NODEIDTYPE_NUMERIC &&
+           dataType->identifier.numeric <= 25 &&
+           isNodeInTree(&server->config.nodestore, constraintDataType,
+                        dataType, &subtypeId, 1))
+            return true;
+    }
+
     return false;
 }
 
@@ -592,7 +599,7 @@ compatibleValueRankArrayDimensions(UA_Int32 valueRank, size_t arrayDimensionsSiz
             return false;
         break;
     default: /* >= 1: the value is an array with the specified number of dimensions */
-        if(valueRank < 0)
+        if(valueRank < (UA_Int32) 0)
             return false;
         /* Must hold if the array has a defined length. Null arrays (length -1)
          * need to be caught before. */
@@ -617,7 +624,7 @@ compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank) {
             return false;
         break;
     case 0: /* the value is an array with one or more dimensions */
-        if(valueRank < 0)
+        if(valueRank < (UA_Int32) 0)
             return false;
         break;
     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
      * be anything... */
-    if(!compatibleDataType(server, &value->type->typeId, targetDataTypeId))
+    if(!compatibleDataType(server, &value->type->typeId, targetDataTypeId, true))
         return false;
 
     /* Array dimensions are checked later when writing the range */
@@ -872,7 +879,7 @@ writeDataTypeAttribute(UA_Server *server, UA_Session *session,
         return UA_STATUSCODE_BADINTERNALERROR;
 
     /* 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;
 
     /* 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);
         server->registeredServersSize--;
 #else
-        server->registeredServersSize = uatomic_add_return(&server->registeredServersSize, -1);
+        UA_atomic_subSize(&server->registeredServersSize, 1);
         UA_Server_delayedCallback(server, freeEntry, registeredServer_entry);
 #endif
         responseHeader->serviceResult = UA_STATUSCODE_GOOD;
@@ -485,7 +485,7 @@ process_RegisterServer(UA_Server *server, UA_Session *session,
 #ifndef UA_ENABLE_MULTITHREADING
         server->registeredServersSize++;
 #else
-        server->registeredServersSize = uatomic_add_return(&server->registeredServersSize, 1);
+        UA_atomic_addSize(&server->registeredServersSize, 1);
 #endif
 
         if(server->registerServerCallback)
@@ -583,7 +583,7 @@ void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic) {
             UA_free(current);
             server->registeredServersSize--;
 #else
-            server->registeredServersSize = uatomic_add_return(&server->registeredServersSize, -1);
+            UA_atomic_subSize(&server->registeredServersSize, 1);
             UA_Server_delayedCallback(server, freeEntry, current);
 #endif
         }

+ 1 - 1
src/server/ua_services_nodemanagement.c

@@ -156,7 +156,7 @@ typeCheckVariableNode(UA_Server *server, UA_Session *session,
         return retval;
 
     /* 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;
 
     /* 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/. 
  *
  *    Copyright 2018 (c) Julius Pfrommer, Fraunhofer IOSB
+ *    Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA
  */
 
 #include "ua_session.h"
 #ifdef UA_ENABLE_SUBSCRIPTIONS
-#include "server/ua_subscription.h"
+#include "ua_subscription.h"
+#include "ua_server_internal.h"
 #endif
 
 UA_Session adminSession = {
@@ -102,6 +104,14 @@ void UA_Session_addSubscription(UA_Session *session, UA_Subscription *newSubscri
     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_Session_deleteSubscription(UA_Server *server, UA_Session *session,
                               UA_UInt32 subscriptionId) {
@@ -109,9 +119,18 @@ UA_Session_deleteSubscription(UA_Server *server, UA_Session *session,
     if(!sub)
         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);
-    UA_Subscription_deleteMembers(sub, server);
-    UA_free(sub);
+
     if(session->numSubscriptions > 0) {
         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
      * available */
     LIST_REMOVE(sentry, pointers);
-    UA_atomic_add(&sm->currentSessionCount, (UA_UInt32)-1);
+    UA_atomic_subUInt32(&sm->currentSessionCount, 1);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -141,7 +141,7 @@ UA_SessionManager_createSession(UA_SessionManager *sm, UA_SecureChannel *channel
     if(!newentry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
-    UA_atomic_add(&sm->currentSessionCount, 1);
+    UA_atomic_addUInt32(&sm->currentSessionCount, 1);
     UA_Session_init(&newentry->session);
     newentry->session.sessionId = UA_NODEID_GUID(1, UA_Guid_random());
     newentry->session.header.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random());

+ 36 - 25
src/ua_securechannel.c

@@ -30,7 +30,7 @@
     UA_SYMMETRIC_ALG_SECURITY_HEADER_LENGTH)
 
 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
 UA_THREAD_LOCAL UA_StatusCode decrypt_verifySignatureFailure;
@@ -50,7 +50,19 @@ UA_SecureChannel_init(UA_SecureChannel *channel,
     channel->state = UA_SECURECHANNELSTATE_FRESH;
     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);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
@@ -130,7 +142,7 @@ UA_SecureChannel_generateNewKeys(UA_SecureChannel *channel) {
         getLocalEncryptionKeyLength(securityPolicy, channel->channelContext);
     const size_t buffSize = symmetricModule->encryptionBlockSize +
                             symmetricModule->signingKeyLength + encryptionKeyLength;
-    UA_ByteString buffer = {buffSize, (UA_Byte *) UA_alloca(buffSize)};
+    UA_ByteString buffer = {buffSize, (UA_Byte *)UA_alloca(buffSize)};
 
     /* Remote keys */
     UA_StatusCode retval = symmetricModule->generateKey(securityPolicy, &channel->localNonce,
@@ -205,9 +217,9 @@ calculatePaddingAsym(const UA_SecurityPolicy *securityPolicy, const void *channe
         ++paddingBytes;
     size_t padding = (plainTextBlockSize - ((bytesToWrite + signatureSize + paddingBytes) %
                                             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
@@ -230,7 +242,7 @@ hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start, const UA_Byt
 
     /* Add the SecurityHeaderLength */
     *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 */
     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 +
                       UA_SEQUENCE_HEADER_LENGTH + securityHeaderLength];
         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 extraPaddingSize = 0;
         UA_UInt16 totalPaddingSize =
@@ -310,7 +322,7 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 r
     }
 
     /* 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;
     if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
        channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
@@ -344,7 +356,7 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 r
 
     UA_SequenceHeader seqHeader;
     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],
                               &header_pos, &buf_end, NULL, NULL);
 
@@ -399,12 +411,12 @@ UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 r
 static UA_UInt16
 calculatePaddingSym(const UA_SecurityPolicy *securityPolicy, const void *channelContext,
                     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;
 }
 
@@ -440,7 +452,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
     /* Will this chunk surpass the capacity of the SecureChannel for the message? */
     UA_Byte *buf_body_start = mc->messageBuffer.data + UA_SECURE_MESSAGE_HEADER_LENGTH;
     const UA_Byte *buf_body_end = mc->buf_pos;
-    size_t bodyLength = (uintptr_t) buf_body_end - (uintptr_t) buf_body_start;
+    size_t bodyLength = (uintptr_t)buf_body_end - (uintptr_t)buf_body_start;
     mc->messageSizeSoFar += bodyLength;
     mc->chunksSoFar++;
     if(mc->messageSizeSoFar > connection->remoteConf.maxMessageSize &&
@@ -476,7 +488,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
     }
 
     /* 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;
     if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
        channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
@@ -490,7 +502,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
     UA_SecureConversationMessageHeader respHeader;
     respHeader.secureChannelId = channel->securityToken.channelId;
     respHeader.messageHeader.messageTypeAndChunkType = mc->messageType;
-    respHeader.messageHeader.messageSize = (UA_UInt32) total_length;
+    respHeader.messageHeader.messageSize = (UA_UInt32)total_length;
     if(mc->final)
         respHeader.messageHeader.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL;
     else
@@ -506,7 +518,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
 
     UA_SequenceHeader seqHeader;
     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],
                            &header_pos, &mc->buf_end, NULL, NULL);
 
@@ -545,7 +557,7 @@ sendSymmetricChunk(UA_MessageContext *mc) {
 static UA_StatusCode
 sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos, const UA_Byte **buf_end) {
     /* Set buf values from encoding in the messagecontext */
-    UA_MessageContext *mc = (UA_MessageContext *) data;
+    UA_MessageContext *mc = (UA_MessageContext *)data;
     mc->buf_pos = *buf_pos;
     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 */
     if(!ch) {
-        ch = (struct ChunkEntry *) UA_malloc(sizeof(struct ChunkEntry));
+        ch = (struct ChunkEntry *)UA_malloc(sizeof(struct ChunkEntry));
         if(!ch)
             return UA_STATUSCODE_BADOUTOFMEMORY;
         ch->requestId = requestId;
@@ -769,7 +781,7 @@ decryptChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cry
         if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
            (messageType == UA_MESSAGETYPE_OPN &&
             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);
             if(keyLength > 2048) {
@@ -967,8 +979,7 @@ UA_SecureChannel_processChunk(UA_SecureChannel *channel, UA_ByteString *chunk,
         sequenceNumberCallback = processSequenceNumberAsym;
         break;
     }
-    default:
-        return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
+    default:return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
     }
 
     /* Decrypt message */

+ 8 - 0
src/ua_types_encoding_binary.c

@@ -1324,8 +1324,16 @@ DECODE_BINARY(DiagnosticInfo) {
             UA_calloc(1, sizeof(UA_DiagnosticInfo));
         if(!dst->innerDiagnosticInfo)
             return UA_STATUSCODE_BADOUTOFMEMORY;
+
+        /* Check the recursion limit */
+        if(ctx->depth > UA_ENCODING_MAX_RECURSION)
+            return UA_STATUSCODE_BADENCODINGERROR;
+        ctx->depth++;
+
         dst->hasInnerDiagnosticInfo = true;
         ret |= DECODE_DIRECT(dst->innerDiagnosticInfo, DiagnosticInfo);
+
+        ctx->depth--;
     }
     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
-UA_atomic_add(volatile uint32_t *addr, uint32_t increase) {
+UA_atomic_addUInt32(volatile uint32_t *addr, uint32_t increase) {
 #ifndef UA_ENABLE_MULTITHREADING
     *addr += increase;
     return *addr;
@@ -120,6 +120,48 @@ UA_atomic_add(volatile uint32_t *addr, uint32_t increase) {
 #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
  * ----------------- */
 

+ 34 - 0
tests/client/check_client.c

@@ -113,6 +113,39 @@ START_TEST(Client_endpoints) {
 }
 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) {
     UA_Client *client = UA_Client_new(UA_ClientConfig_default);
     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_username);
     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_delete_without_connect);
     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_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;
     countNotificationReceived++;
 }

+ 1 - 1
tests/fuzz/corpus_generator.c

@@ -360,7 +360,7 @@ translateBrowsePathsToNodeIdsRequest(UA_Client *client) {
 
 
 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__
 
-#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 "testing_policy.h"
 #include "check.h"
@@ -339,7 +340,8 @@ TestingPolicy(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
     funcsCalled = fCalled;
     policy->policyContext = (void *) funcsCalled;
     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);
 
     policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_testing;

+ 1 - 1
tools/amalgamate.py

@@ -76,7 +76,7 @@ if is_c:
 else:
     file.write(u'''#ifndef %s
 #define %s
-''' % (outname.upper() + u"_H_", outname.upper() + u"_H_") )
+''' % (outname.upper() + u"_H_", outname.upper() + u"_H_"))
 
 for fname in args.inputs:
     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)
         members = "static UA_DataTypeMember %s_members[%s] = {" % (self.name, len(self.members))
         before = None
+        i = 0
+        size = len(self.members)
         for index, member in enumerate(self.members):
+            i += 1
             m = "\n{\n    UA_TYPENAME(\"%s\") /* .memberName */\n" % member.name
             m += "    %s_%s, /* .memberTypeIndex */\n" % (member.memberType.outname.upper(), member.memberType.name.upper())
             m += "    "
@@ -126,7 +129,9 @@ class Type(object):
                     m += " - sizeof(UA_%s)," % before.memberType.name
             m += " /* .padding */\n"
             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
             before = member
         return members + "};"
@@ -501,7 +506,9 @@ printh("extern UA_EXPORT const UA_DataType " + outname.upper() + "[" + outname.u
 
 i = 0
 for t in filtered_types:
-    printh("\n/**\n * " +  t.name)
+    if i != 0:
+        printh("\n")
+    printh("/**\n * " +  t.name)
     printh(" * " + "^" * len(t.name))
     if t.description == "":
         printh(" */")
@@ -512,9 +519,12 @@ for t in filtered_types:
     printh("#define " + outname.upper() + "_" + t.name.upper() + " " + str(i))
     i += 1
 
+i = 0
 # Generate alias for 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))
     if t.description == "":
         printh(" */")
@@ -523,6 +533,7 @@ for t in filtered_opaque_types:
     if type(t) != BuiltinType:
         printh(t.typedef_h() + "\n")
     printh("#define " + outname.upper() + "_" + t.name.upper() + " " + outname.upper() + "_" + get_base_type_for_opaque(t.name)['name'].upper())
+    i += 1
 
 printh('''
 #ifdef __cplusplus
@@ -585,7 +596,7 @@ for t in filtered_types:
 
 printc("const UA_DataType %s[%s_COUNT] = {" % (outname.upper(), outname.upper()))
 for t in filtered_types:
-    printc("")
+#    printc("")
     printc("/* " + t.name + " */")
     printc(t.datatype_c() + ",")
 printc("};\n")

+ 3 - 3
tools/generate_statuscode_descriptions.py

@@ -58,13 +58,13 @@ static const UA_StatusCodeName statusCodeDescriptions[%i] = {
 ''' % (count, count))
 
 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"}
 };
 
 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[statusCodeDescriptionsSize-1].name;

+ 3 - 4
tools/nodeset_compiler/backend_open62541.py

@@ -226,7 +226,7 @@ extern UA_StatusCode %s(UA_Server *server);
         # Print node
         if not node.hidden:
             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)
             if code is None:
                 writec("/* Ignored. No parent */")
@@ -241,7 +241,7 @@ extern UA_StatusCode %s(UA_Server *server);
             
         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)
         writec("return " + code + "\n}\n")
 
@@ -249,8 +249,7 @@ extern UA_StatusCode %s(UA_Server *server);
     
     
     writec("""
-UA_StatusCode %s(UA_Server *server) {  // NOLINT
-
+UA_StatusCode %s(UA_Server *server) {
 UA_StatusCode retVal = UA_STATUSCODE_GOOD;""" % (outfilebase))
     # Generate namespaces (don't worry about duplicates)
     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):
     if not value:
-        return "UA_NODEID_NUMERIC(0,0)"
+        return "UA_NODEID_NUMERIC(0, 0)"
     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:
-        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..")
 
 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) + ", " +
         str(binaryEncodingId.i) + ");")
     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.
     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)(" +
                 "pos" + instanceName + "-" + instanceName + "->content.encoded.body.data);")
     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, " +
                 instanceName + "_encOffset);")
     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) + ");")
         for i in range(0, parentNode.valueRank):
             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 + ");")
     else:
         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)
                     code.append(
                         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)) + ", " +
                         getTypesArrayForValue(nodeset, node.value[0]) + ");")
     else:
@@ -398,7 +398,7 @@ def generateValueCode(node, parentNode, nodeset, bootstrapping=True, max_string_
                 code.append("UA_" + node.value[0].__class__.__name__ + " *" + valueName + " = " +
                             generateNodeValueCode(node.value[0], instanceName, max_string_length=max_string_length) + ";")
                 code.append(
-                    "UA_Variant_setScalar( &attr.value, " + valueName + ", " +
+                    "UA_Variant_setScalar(&attr.value, " + valueName + ", " +
                     getTypesArrayForValue(nodeset, node.value[0]) + ");")
 
                 # 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();")
                 code.append("*" + valueName + " = " + generateNodeValueCode(node.value[0], instanceName, asIndirect=True, max_string_length=max_string_length) + ";")
                 code.append(
-                        "UA_Variant_setScalar( &attr.value, " + valueName + ", " +
+                        "UA_Variant_setScalar(&attr.value, " + valueName + ", " +
                         getTypesArrayForValue(nodeset, node.value[0]) + ");")
                 codeCleanup.append("UA_{0}_delete({1});".format(
                     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 apt-get update -qq
-	sudo apt-get install -y liburcu4 liburcu-dev
 	echo -en 'travis_fold:end:script.before_install.external\\r'
 
 	echo "=== Installing python packages ===" && echo -en 'travis_fold:start:before_install.python\\r'
 	pip install --user cpp-coveralls
 	pip install --user sphinx
 	pip install --user sphinx_rtd_theme
+	pip install --user cpplint
 	echo -en 'travis_fold:end:script.before_install.python\\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
 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
 if ! [ -z ${FUZZER+x} ]; then
     # 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
 
 brew install check
-brew install userspace-rcu
 brew install valgrind
 brew install graphviz
 brew install python