Browse Source

fix remaining issues with g++; all examples compile as C++

Julius Pfrommer 7 years ago
parent
commit
7aa39e4a31

+ 1 - 1
CMakeLists.txt

@@ -114,7 +114,7 @@ mark_as_advanced(UA_COMPILE_AS_CXX)
 
 list(APPEND open62541_LIBRARIES "") # Collect libraries
 
-if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
+if(NOT UA_COMPILE_AS_CXX AND (CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang"))
     # Compiler
     add_definitions(-std=c99 -pipe -Wall -Wextra -Werror -Wformat -Wno-unused-parameter
                     -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare

+ 25 - 41
examples/CMakeLists.txt

@@ -7,7 +7,7 @@ else()
     add_definitions(-DUA_NO_AMALGAMATION)
 endif()
 
-list(APPEND LIBS ${open62541_LIBRARIES} open62541)
+list(APPEND LIBS ${open62541_LIBRARIES})
 if(NOT WIN32)
   list(APPEND LIBS pthread)
   if (NOT APPLE)
@@ -20,63 +20,54 @@ if(UA_ENABLE_MULTITHREADING)
   list(APPEND LIBS urcu-cds urcu urcu-common)
 endif(UA_ENABLE_MULTITHREADING)
 
+macro(add_example EXAMPLE_NAME EXAMPLE_SOURCE)
+  add_executable(${EXAMPLE_NAME} $<TARGET_OBJECTS:open62541-object> ${EXAMPLE_SOURCE})
+  target_link_libraries(${EXAMPLE_NAME} ${LIBS})
+  if(UA_COMPILE_AS_CXX)
+    set_source_files_properties(${EXAMPLE_SOURCE} PROPERTIES LANGUAGE CXX)
+  endif()
+endmacro()
+
 ##################
 # Example Server #
 ##################
 
-add_executable(server server.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(server ${LIBS})
-
-if(UA_ENABLE_NONSTANDARD_UDP)
-  add_executable(server_udp server_udp.c $<TARGET_OBJECTS:open62541-object> ${PROJECT_SOURCE_DIR}/plugins/ua_network_udp.c)
-  target_link_libraries(server_udp ${LIBS})
-endif()
+add_example(server server.c)
 
 ##################
 # Example Client #
 ##################
 
-add_executable(client client.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(client ${LIBS})
+add_example(client client.c)
 
 ####################
 # Feature Examples #
 ####################
 
-add_executable(server_variable server_variable.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(server_variable ${LIBS})
+add_example(server_variable server_variable.c)
 
-add_executable(server_mainloop server_mainloop.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(server_mainloop ${LIBS})
+add_example(server_mainloop server_mainloop.c)
 
-add_executable(server_datasource server_datasource.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(server_datasource ${LIBS})
+add_example(server_datasource server_datasource.c)
 
-add_executable(server_firstSteps server_firstSteps.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(server_firstSteps ${LIBS})
+add_example(server_firstSteps server_firstSteps.c)
 
-add_executable(server_instantiation server_instantiation.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(server_instantiation ${LIBS})
+add_example(server_instantiation server_instantiation.c)
 
-add_executable(server_repeated_job server_repeated_job.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(server_repeated_job ${LIBS})
+add_example(server_repeated_job server_repeated_job.c)
 
-add_executable(server_readspeed server_readspeed.c $<TARGET_OBJECTS:open62541-object>)
+add_example(server_readspeed server_readspeed.c)
 target_include_directories(server_readspeed PRIVATE ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/deps) # needs an internal header
-target_link_libraries(server_readspeed ${LIBS})
 
-add_executable(server_inheritance server_inheritance.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(server_inheritance ${LIBS})
+add_example(server_inheritance server_inheritance.c)
 
 if(UA_BUILD_EXAMPLES_NODESET_COMPILER)
-  add_executable(server_nodeset server_nodeset.c ${PROJECT_BINARY_DIR}/src_generated/nodeset.c $<TARGET_OBJECTS:open62541-object>)
-  target_link_libraries(server_nodeset ${LIBS})
+  add_executable(server_nodeset "server_nodeset.c ${PROJECT_BINARY_DIR}/src_generated/nodeset.c")
   target_include_directories(server_nodeset PRIVATE ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/deps) # needs an internal header
 endif()
 
 if(UA_ENABLE_METHODCALLS)
-  add_executable(server_method server_method.c $<TARGET_OBJECTS:open62541-object>)
-  target_link_libraries(server_method ${LIBS})
+  add_example(server_method server_method.c)
 endif()
 
 if(UA_BUILD_SELFSIGNED_CERTIFICATE)
@@ -85,24 +76,17 @@ if(UA_BUILD_SELFSIGNED_CERTIFICATE)
                      COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py ${CMAKE_CURRENT_BINARY_DIR}
                      DEPENDS ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py
                              ${PROJECT_SOURCE_DIR}/tools/certs/localhost.cnf)
-
   add_custom_target(selfsigned ALL DEPENDS server_cert.der ca.crt)
-
   add_executable(server_certificate server_certificate.c $<TARGET_OBJECTS:open62541-object> server_cert.der ca.crt)
   target_link_libraries(server_certificate ${LIBS})
 endif()
 
 if(UA_ENABLE_DISCOVERY)
+    add_example(discovery_server_discovery discovery/server_discovery.c)
 
-    add_executable(discovery_server_discovery discovery/server_discovery.c)
-    target_link_libraries(discovery_server_discovery ${LIBS})
-
-    add_executable(discovery_server_register discovery/server_register.c)
-    target_link_libraries(discovery_server_register ${LIBS})
+    add_example(discovery_server_register discovery/server_register.c)
 
-    add_executable(discovery_client_find_servers discovery/client_find_servers.c)
-    target_link_libraries(discovery_client_find_servers ${LIBS})
+    add_example(discovery_client_find_servers discovery/client_find_servers.c)
 endif()
 
-add_executable(client_firstSteps client_firstSteps.c $<TARGET_OBJECTS:open62541-object>)
-target_link_libraries(client_firstSteps ${LIBS})
+add_example(client_firstSteps client_firstSteps.c)

+ 0 - 1
examples/client_firstSteps.c

@@ -2,7 +2,6 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 #include <stdio.h>
-#include <inttypes.h>
 
 #ifdef UA_NO_AMALGAMATION
 #include "ua_client.h"

+ 1 - 2
examples/discovery/client_find_servers.c

@@ -6,7 +6,6 @@
  */
 
 #include <stdio.h>
-#include <inttypes.h>
 #include <stdlib.h>
 
 #ifdef UA_NO_AMALGAMATION
@@ -161,7 +160,7 @@ int main(void) {
 
         UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
 
-        char* discoveryUrl = malloc(sizeof(char)*description->discoveryUrls[0].length+1);
+        char* discoveryUrl = (char*)malloc(sizeof(char)*description->discoveryUrls[0].length+1);
         memcpy( discoveryUrl, description->discoveryUrls[0].data, description->discoveryUrls[0].length );
         discoveryUrl[description->discoveryUrls[0].length] = '\0';
 

+ 13 - 9
examples/discovery/server_register.c

@@ -112,8 +112,8 @@ static void periodicServerRegister(UA_Server *server, void *data) {
         // as long as next retry is smaller than 10 minutes, retry
         if (nextInterval < 10*60) {
             UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "Retrying registration in %d seconds", nextInterval);
-            struct PeriodicServerRegisterJob *newRetryJob = malloc(sizeof(struct PeriodicServerRegisterJob));
-            newRetryJob->job = malloc(sizeof(UA_Job));
+            struct PeriodicServerRegisterJob *newRetryJob = (struct PeriodicServerRegisterJob*)malloc(sizeof(struct PeriodicServerRegisterJob));
+            newRetryJob->job = (UA_Job*)malloc(sizeof(UA_Job));
             newRetryJob->this_interval = nextInterval;
 
             newRetryJob->job->type = UA_JOBTYPE_METHODCALL;
@@ -142,8 +142,10 @@ int main(int argc, char** argv) {
     UA_Int32 myInteger = 42;
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    UA_DataSource dateDataSource = (UA_DataSource) {
-            .handle = &myInteger, .read = readInteger, .write = writeInteger};
+    UA_DataSource dateDataSource;
+	dateDataSource.handle = &myInteger;
+	dateDataSource.read = readInteger;
+	dateDataSource.write = writeInteger;
     UA_VariableAttributes attr;
     UA_VariableAttributes_init(&attr);
     attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
@@ -156,15 +158,17 @@ int main(int argc, char** argv) {
 
 
     // registering the server should be done periodically. Approx. every 10 minutes. The first call will be in 10 Minutes.
-    UA_Job job = {.type = UA_JOBTYPE_METHODCALL,
-            .job.methodCall = {.method = periodicServerRegister, .data = NULL} };
+    UA_Job job;
+    job.type = UA_JOBTYPE_METHODCALL;
+    job.job.methodCall.data = NULL;
+    job.job.methodCall.method = periodicServerRegister;
     UA_Server_addRepeatedJob(server, job, 10*60*1000, NULL);
 
     // Register the server with the discovery server.
     // Delay this first registration until the server is fully initialized
     // will be freed in the callback
-    struct PeriodicServerRegisterJob *newRetryJob = malloc(sizeof(struct PeriodicServerRegisterJob));
-    newRetryJob->job = malloc(sizeof(UA_Job));
+    struct PeriodicServerRegisterJob *newRetryJob = (struct PeriodicServerRegisterJob*)malloc(sizeof(struct PeriodicServerRegisterJob));
+    newRetryJob->job = (UA_Job*)malloc(sizeof(UA_Job));
     newRetryJob->this_interval = 0;
     newRetryJob->job->type = UA_JOBTYPE_METHODCALL;
     newRetryJob->job->job.methodCall.method = periodicServerRegister;
@@ -194,4 +198,4 @@ int main(int argc, char** argv) {
     nl.deleteMembers(&nl);
 
     return (int)retval;
-}
+}

+ 7 - 4
examples/server.c

@@ -38,7 +38,7 @@ static UA_ByteString loadCertificate(void) {
 
     fseek(fp, 0, SEEK_END);
     certificate.length = (size_t)ftell(fp);
-    certificate.data = malloc(certificate.length*sizeof(UA_Byte));
+    certificate.data = (UA_Byte*)malloc(certificate.length*sizeof(UA_Byte));
     if(!certificate.data)
         return certificate;
 
@@ -86,7 +86,7 @@ helloWorld(void *methodHandle, const UA_NodeId *objectId,
     UA_String hello = UA_STRING("Hello ");
     UA_String greet;
     greet.length = hello.length + name->length;
-    greet.data = malloc(greet.length);
+    greet.data = (UA_Byte*)malloc(greet.length);
     memcpy(greet.data, hello.data, hello.length);
     memcpy(greet.data + hello.length, name->data, name->length);
     UA_Variant_setScalarCopy(output, &greet, &UA_TYPES[UA_TYPES_STRING]);
@@ -143,7 +143,10 @@ int main(int argc, char** argv) {
     UA_Variant_deleteMembers(&myVar.value);
 
     /* add a variable with the datetime data source */
-    UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .write = NULL};
+    UA_DataSource dateDataSource;
+	dateDataSource.handle = NULL;
+	dateDataSource.read = readTimeData;
+	dateDataSource.write = NULL;
     UA_VariableAttributes v_attr;
     UA_VariableAttributes_init(&v_attr);
     v_attr.description = UA_LOCALIZEDTEXT("en_US","current time");
@@ -268,7 +271,7 @@ int main(int argc, char** argv) {
 
         /* add an matrix node for every built-in type */
         void* myMultiArray = UA_Array_new(9, &UA_TYPES[type]);
-        attr.value.arrayDimensions = UA_Array_new(2, &UA_TYPES[UA_TYPES_INT32]);
+        attr.value.arrayDimensions = (UA_UInt32*)UA_Array_new(2, &UA_TYPES[UA_TYPES_INT32]);
         attr.value.arrayDimensions[0] = 3;
         attr.value.arrayDimensions[1] = 3;
         attr.value.arrayDimensionsSize = 2;

+ 5 - 3
examples/server_datasource.c

@@ -61,8 +61,10 @@ int main(int argc, char** argv) {
     UA_Int32 myInteger = 42;
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    UA_DataSource dateDataSource = (UA_DataSource) {
-        .handle = &myInteger, .read = readInteger, .write = writeInteger};
+    UA_DataSource dataSource;
+	dataSource.handle = &myInteger;
+	dataSource.read = readInteger;
+	dataSource.write = NULL;
     UA_VariableAttributes attr;
     UA_VariableAttributes_init(&attr);
     attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
@@ -71,7 +73,7 @@ int main(int argc, char** argv) {
     UA_Server_addDataSourceVariableNode(server, myIntegerNodeId,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource, NULL);
+                                        myIntegerName, UA_NODEID_NULL, attr, dataSource, NULL);
 
     UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);

+ 4 - 4
examples/server_mainloop.c

@@ -40,14 +40,14 @@ int main(int argc, char** argv) {
     config.networkLayersSize = 1;
     UA_Server *server = UA_Server_new(config);
 
-    UA_StatusCode retval = UA_Server_run_startup(server);
-    if(retval != UA_STATUSCODE_GOOD)
-        goto cleanup;
-
     /* Should the server networklayer block (with a timeout) until a message
        arrives or should it return immediately? */
     UA_Boolean waitInternal = false;
 
+    UA_StatusCode retval = UA_Server_run_startup(server);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto cleanup;
+
     while(running) {
         /* timeout is the maximum possible delay (in millisec) until the next
            _iterate call. Otherwise, the server might miss an internal timeout

+ 2 - 2
examples/server_method.c

@@ -27,7 +27,7 @@ helloWorldMethod(void *handle, const UA_NodeId *objectId,
     UA_String *inputStr = (UA_String*)input->data;
     UA_String tmp = UA_STRING_ALLOC("Hello ");
     if(inputStr->length > 0) {
-        tmp.data = realloc(tmp.data, tmp.length + inputStr->length);
+        tmp.data = (UA_Byte*)realloc(tmp.data, tmp.length + inputStr->length);
         memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length);
         tmp.length += inputStr->length;
     }
@@ -60,7 +60,7 @@ fooBarMethod(void *handle, const UA_NodeId *objectId,
     UA_String *inputStr = (UA_String*)input->data;
     UA_String tmp = UA_STRING_ALLOC("FooBar! ");
     if(inputStr->length > 0) {
-        tmp.data = realloc(tmp.data, tmp.length + inputStr->length);
+        tmp.data = (UA_Byte*)realloc(tmp.data, tmp.length + inputStr->length);
         memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length);
         tmp.length += inputStr->length;
     }

+ 4 - 2
examples/server_repeated_job.c

@@ -35,8 +35,10 @@ int main(int argc, char** argv) {
     UA_Server *server = UA_Server_new(config);
 
     /* add a repeated job to the server */
-    UA_Job job = {.type = UA_JOBTYPE_METHODCALL,
-                  .job.methodCall = {.method = testCallback, .data = NULL} };
+    UA_Job job;
+    job.type = UA_JOBTYPE_METHODCALL;
+    job.job.methodCall.data = NULL;
+    job.job.methodCall.method = testCallback;
     UA_Server_addRepeatedJob(server, job, 2000, NULL); // call every 2 sec
 
     UA_StatusCode retval = UA_Server_run(server, &running);

+ 5 - 8
include/ua_config.h.in

@@ -65,14 +65,11 @@ extern "C" {
 #include "ms_stdint.h" /* Includes stdint.h or workaround for older Visual Studios */
 
 #ifndef __cplusplus
-# if defined(_MSC_VER) && _MSC_VER < 1800 
-    /* Workaround for old Visual Studios */
-    typedef uint8_t bool;
-#  define true 1
-#  define false 0
-# else
-#  include <stdbool.h> /* Default: C99 Boolean */
-# endif
+# include <stdbool.h> /* C99 Boolean */
+/* Manual Boolean:
+typedef uint8_t bool;
+#define true 1
+#define false 0 */
 #endif
 
 /* Manually define some function on libc */

+ 4 - 4
plugins/ua_config_standard.h

@@ -4,14 +4,14 @@
 #ifndef UA_CONFIG_STANDARD_H_
 #define UA_CONFIG_STANDARD_H_
 
-#include "ua_server.h"
-#include "ua_client.h"
-#include "ua_client_highlevel.h"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#include "ua_server.h"
+#include "ua_client.h"
+#include "ua_client_highlevel.h"
+
 extern UA_EXPORT const UA_ServerConfig UA_ServerConfig_standard;
 extern UA_EXPORT const UA_ClientConfig UA_ClientConfig_standard;
 

+ 4 - 2
src/client/ua_client.c

@@ -734,6 +734,10 @@ processServiceResponse(struct ResponseDescription *rd, UA_SecureChannel *channel
     UA_ResponseHeader *respHeader = (UA_ResponseHeader*)rd->response;
     rd->processed = true;
 
+    /* Forward declaration for the goto */
+    size_t offset = 0;
+    UA_NodeId responseId;
+
     if(messageType != UA_MESSAGETYPE_MSG) {
         UA_LOG_ERROR(rd->client->config.logger, UA_LOGCATEGORY_CLIENT,
                      "Server replied with the wrong message type");
@@ -753,8 +757,6 @@ processServiceResponse(struct ResponseDescription *rd, UA_SecureChannel *channel
     }
 
     /* Check that the response type matches */
-    size_t offset = 0;
-    UA_NodeId responseId;
     retval = UA_NodeId_decodeBinary(message, &offset, &responseId);
     if(retval != UA_STATUSCODE_GOOD)
         goto finish;

+ 2 - 1
src/client/ua_client_highlevel.c

@@ -382,12 +382,13 @@ UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId
     request.nodesToReadSize = 1;
     UA_ReadResponse response = UA_Client_Service_read(client, request);
     UA_StatusCode retval = response.responseHeader.serviceResult;
+    UA_DataValue *res = response.results;
+
     if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
         retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
     if(retval != UA_STATUSCODE_GOOD)
         goto cleanup;
 
-    UA_DataValue *res = response.results;
     if(res->hasStatus != UA_STATUSCODE_GOOD)
         retval = res->hasStatus;
     else if(!res->hasValue || UA_Variant_isScalar(&res->value))

+ 11 - 10
src/client/ua_client_highlevel_subscriptions.c

@@ -19,13 +19,15 @@ UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
 
     UA_CreateSubscriptionResponse response = UA_Client_Service_createSubscription(client, request);
     UA_StatusCode retval = response.responseHeader.serviceResult;
-    if(retval != UA_STATUSCODE_GOOD)
-        goto cleanup;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_CreateSubscriptionResponse_deleteMembers(&response);
+        return retval;
+    }
 
     UA_Client_Subscription *newSub = (UA_Client_Subscription *)UA_malloc(sizeof(UA_Client_Subscription));
     if(!newSub) {
-        retval = UA_STATUSCODE_BADOUTOFMEMORY;
-        goto cleanup;
+        UA_CreateSubscriptionResponse_deleteMembers(&response);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
     }
 
     LIST_INIT(&newSub->MonitoredItems);
@@ -40,9 +42,8 @@ UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
     if(newSubscriptionId)
         *newSubscriptionId = newSub->SubscriptionID;
 
- cleanup:
     UA_CreateSubscriptionResponse_deleteMembers(&response);
-    return retval;
+    return UA_STATUSCODE_GOOD;
 }
 
 /* remove the subscription remotely */
@@ -104,8 +105,8 @@ UA_Client_Subscriptions_forceDelete(UA_Client *client,
 UA_StatusCode
 UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                          UA_NodeId nodeId, UA_UInt32 attributeID,
-                                         UA_MonitoredItemHandlingFunction handlingFunction,
-                                         void *handlingContext, UA_UInt32 *newMonitoredItemId) {
+                                         UA_MonitoredItemHandlingFunction hf,
+                                         void *hfContext, UA_UInt32 *newMonitoredItemId) {
     UA_Client_Subscription *sub;
     LIST_FOREACH(sub, &client->subscriptions, listEntry) {
         if(sub->SubscriptionID == subscriptionId)
@@ -151,8 +152,8 @@ UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscripti
     newMon->SamplingInterval = sub->PublishingInterval;
     newMon->QueueSize = 1;
     newMon->DiscardOldest = true;
-    newMon->handler = handlingFunction;
-    newMon->handlerContext = handlingContext;
+    newMon->handler = hf;
+    newMon->handlerContext = hfContext;
     newMon->MonitoredItemId = response.results[0].monitoredItemId;
     LIST_INSERT_HEAD(&sub->MonitoredItems, newMon, listEntry);
     *newMonitoredItemId = newMon->MonitoredItemId;

+ 8 - 0
src/server/ua_securechannel_manager.h

@@ -1,6 +1,10 @@
 #ifndef UA_CHANNEL_MANAGER_H_
 #define UA_CHANNEL_MANAGER_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "ua_util.h"
 #include "ua_server.h"
 #include "ua_securechannel.h"
@@ -42,4 +46,8 @@ UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_UInt32 channelId);
 UA_StatusCode
 UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt32 channelId);
 
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
 #endif /* UA_CHANNEL_MANAGER_H_ */

+ 4 - 4
src/server/ua_server.c

@@ -425,14 +425,14 @@ readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp
     return UA_STATUSCODE_GOOD;
 }
 
-static void copyNames(UA_Node *node, char *name) {
+static void copyNames(UA_Node *node, const char *name) {
     node->browseName = UA_QUALIFIEDNAME_ALLOC(0, name);
     node->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", name);
     node->description = UA_LOCALIZEDTEXT_ALLOC("en_US", name);
 }
 
 static void
-addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid,
+addDataTypeNode(UA_Server *server, const char* name, UA_UInt32 datatypeid,
                 UA_Boolean isAbstract, UA_UInt32 parent) {
     UA_DataTypeNode *datatype = UA_NodeStore_newDataTypeNode();
     copyNames((UA_Node*)datatype, name);
@@ -443,7 +443,7 @@ addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid,
 }
 
 static void
-addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttypeid,
+addObjectTypeNode(UA_Server *server, const char* name, UA_UInt32 objecttypeid,
                   UA_UInt32 parent, UA_UInt32 parentreference) {
     UA_ObjectTypeNode *objecttype = UA_NodeStore_newObjectTypeNode();
     copyNames((UA_Node*)objecttype, name);
@@ -453,7 +453,7 @@ addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttypeid,
 }
 
 static UA_VariableTypeNode*
-createVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid,
+createVariableTypeNode(UA_Server *server, const char* name, UA_UInt32 variabletypeid,
                        UA_Boolean abstract) {
     UA_VariableTypeNode *variabletype = UA_NodeStore_newVariableTypeNode();
     copyNames((UA_Node*)variabletype, name);

+ 8 - 0
src/server/ua_server_internal.h

@@ -1,6 +1,10 @@
 #ifndef UA_SERVER_INTERNAL_H_
 #define UA_SERVER_INTERNAL_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "ua_util.h"
 #include "ua_server.h"
 #include "ua_server_external_ns.h"
@@ -262,4 +266,8 @@ void Service_Call_single(UA_Server *server, UA_Session *session,
 /* Periodic task to clean up the discovery registry */
 void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic);
 
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
 #endif /* UA_SERVER_INTERNAL_H_ */

+ 1 - 1
src/server/ua_services_nodemanagement.c

@@ -271,7 +271,7 @@ instantiateNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
         if(olm->constructor)
             UA_Server_editNode(server, session, nodeId,
                                (UA_EditNodeCallback)setObjectInstanceHandle,
-                               olm->constructor);
+                               (void*)olm->constructor);
     }
 
     /* Add a hasType reference */

+ 24 - 19
src/server/ua_services_subscription.c

@@ -392,22 +392,36 @@ void Service_SetMonitoringMode(UA_Server *server, UA_Session *session,
     }
 }
 
+/* TODO: Unify with senderror in ua_server_binary.c */
+static void
+subscriptionSendError(UA_SecureChannel *channel, UA_UInt32 requestHandle,
+                      UA_UInt32 requestId, UA_StatusCode error) {
+    UA_PublishResponse err_response;
+    UA_PublishResponse_init(&err_response);
+    err_response.responseHeader.requestHandle = requestHandle;
+    err_response.responseHeader.timestamp = UA_DateTime_now();
+    err_response.responseHeader.serviceResult = error;
+    UA_SecureChannel_sendBinaryMessage(channel, requestId, &err_response,
+                                       &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
+}
 
 void
 Service_Publish(UA_Server *server, UA_Session *session,
                 const UA_PublishRequest *request, UA_UInt32 requestId) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing PublishRequest");
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+
     /* Return an error if the session has no subscription */
     if(LIST_EMPTY(&session->serverSubscriptions)) {
-        retval = UA_STATUSCODE_BADNOSUBSCRIPTION;
-        goto send_error;
+        subscriptionSendError(session->channel, request->requestHeader.requestHandle,
+                              requestId, UA_STATUSCODE_BADNOSUBSCRIPTION);
+        return;
     }
 
     UA_PublishResponseEntry *entry = (UA_PublishResponseEntry *)UA_malloc(sizeof(UA_PublishResponseEntry));
-    if(!entry) {
-        retval = UA_STATUSCODE_BADOUTOFMEMORY;
-        goto send_error;
+	if(!entry) {
+        subscriptionSendError(session->channel, requestId,
+                              request->requestHeader.requestHandle, UA_STATUSCODE_BADOUTOFMEMORY);
+        return;
     }
     entry->requestId = requestId;
 
@@ -420,8 +434,10 @@ Service_Publish(UA_Server *server, UA_Session *session,
                                          &UA_TYPES[UA_TYPES_STATUSCODE]);
         if(!response->results) {
             UA_free(entry);
-            retval = UA_STATUSCODE_BADOUTOFMEMORY;
-            goto send_error;
+            subscriptionSendError(session->channel, requestId,
+                                  request->requestHeader.requestHandle,
+                                  UA_STATUSCODE_BADOUTOFMEMORY);
+            return;
         }
         response->resultsSize = request->subscriptionAcknowledgementsSize;
     }
@@ -457,17 +473,6 @@ Service_Publish(UA_Server *server, UA_Session *session,
             break;
         }
     }
-    return;
-
-    UA_PublishResponse err_response;
- send_error:
-    UA_PublishResponse_init(&err_response);
-    err_response.responseHeader.requestHandle = request->requestHeader.requestHandle;
-    err_response.responseHeader.timestamp = UA_DateTime_now();
-    err_response.responseHeader.serviceResult = retval;
-    UA_assert(err_response.responseHeader.requestHandle != 0);
-    UA_SecureChannel_sendBinaryMessage(session->channel, requestId, &err_response,
-                                       &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
 }
 
 void

+ 6 - 3
src/server/ua_services_view.c

@@ -148,6 +148,7 @@ void
 Service_Browse_single(UA_Server *server, UA_Session *session,
                       struct ContinuationPointEntry *cp, const UA_BrowseDescription *descr,
                       UA_UInt32 maxrefs, UA_BrowseResult *result) { 
+    /* TODO: Split this function and remove goto */
     size_t referencesCount = 0;
     size_t referencesIndex = 0;
     /* set the browsedescription if a cp is given */
@@ -204,6 +205,11 @@ Service_Browse_single(UA_Server *server, UA_Session *session,
         return;
     }
 
+    /* Forward declare for goto */
+    size_t skipped = 0;
+    UA_Boolean isExternal = false;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+
     /* how many references can we return at most? */
     size_t real_maxrefs = maxrefs;
     if(real_maxrefs == 0)
@@ -217,9 +223,6 @@ Service_Browse_single(UA_Server *server, UA_Session *session,
     }
 
     /* loop over the node's references */
-    size_t skipped = 0;
-    UA_Boolean isExternal = false;
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     for(; referencesIndex < node->referencesSize && referencesCount < real_maxrefs; ++referencesIndex) {
         isExternal = false;
         const UA_Node *current =

+ 8 - 0
src/server/ua_session_manager.h

@@ -1,6 +1,10 @@
 #ifndef UA_SESSION_MANAGER_H_
 #define UA_SESSION_MANAGER_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "queue.h"
 #include "ua_server.h"
 #include "ua_util.h"
@@ -34,4 +38,8 @@ UA_SessionManager_removeSession(UA_SessionManager *sm, const UA_NodeId *token);
 UA_Session *
 UA_SessionManager_getSession(UA_SessionManager *sm, const UA_NodeId *token);
 
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
 #endif /* UA_SESSION_MANAGER_H_ */

+ 26 - 26
src/server/ua_subscription.c

@@ -48,20 +48,14 @@ void MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *monitoredItem) {
 
 static void
 ensureSpaceInMonitoredItemQueue(UA_MonitoredItem *mon) {
-    if(mon->currentQueueSize < mon->maxQueueSize) {
+    if(mon->currentQueueSize < mon->maxQueueSize)
         return;
-    }
-
-	MonitoredItem_queuedValue *queueItem =
-		TAILQ_LAST(&mon->queue, memberstruct(UA_MonitoredItem,QueueOfQueueDataValues));
-
-    if(mon->discardOldest) {
+    MonitoredItem_queuedValue *queueItem;
+    if(mon->discardOldest)
         queueItem = TAILQ_FIRST(&mon->queue);
-    } else {
-		queueItem = TAILQ_LAST(&mon->queue,
-		                       memberstruct(UA_MonitoredItem,QueueOfQueueDataValues));
-    }
-
+    else
+        queueItem = TAILQ_LAST(&mon->queue,
+                               memberstruct(UA_MonitoredItem,QueueOfQueueDataValues));
     UA_assert(queueItem); /* When the currentQueueSize > 0, then there is an item */
     TAILQ_REMOVE(&mon->queue, queueItem, listEntry);
     UA_DataValue_deleteMembers(&queueItem->value);
@@ -89,9 +83,13 @@ detectValueChange(UA_MonitoredItem *mon, UA_DataValue *value,
         value->hasSourcePicoseconds = false;
     }
 
-    /* Encode the data for comparison */
+    /* Forward declare before goto */
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    size_t binsize = UA_calcSizeBinary(value, &UA_TYPES[UA_TYPES_DATAVALUE]);
+    size_t encodingOffset = 0;
+    size_t binsize;
+
+    /* Encode the data for comparison */
+    binsize = UA_calcSizeBinary(value, &UA_TYPES[UA_TYPES_DATAVALUE]);
     if(binsize == 0) {
         retval = UA_STATUSCODE_BADINTERNALERROR;
         goto cleanup;
@@ -105,7 +103,6 @@ detectValueChange(UA_MonitoredItem *mon, UA_DataValue *value,
     }
 
     /* Encode the value */
-    size_t encodingOffset = 0;
     retval = UA_encodeBinary(value, &UA_TYPES[UA_TYPES_DATAVALUE],
                              NULL, NULL, encoding, &encodingOffset);
     if(retval != UA_STATUSCODE_GOOD)
@@ -159,6 +156,9 @@ void UA_MoniteredItem_SampleCallback(UA_Server *server, UA_MonitoredItem *monito
     valueEncoding.data = stackValueEncoding;
     valueEncoding.length = UA_VALUENCODING_MAXSTACK;
 
+    /* Forward declaration before goto */
+    MonitoredItem_queuedValue *newQueueItem;
+
     /* Has the value changed? */
     UA_Boolean changed = false;
     UA_StatusCode retval = detectValueChange(monitoredItem, &value,
@@ -167,7 +167,7 @@ void UA_MoniteredItem_SampleCallback(UA_Server *server, UA_MonitoredItem *monito
         goto cleanup;
 
     /* Allocate the entry for the publish queue */
-    MonitoredItem_queuedValue *newQueueItem = (MonitoredItem_queuedValue *)UA_malloc(sizeof(MonitoredItem_queuedValue));
+    newQueueItem = (MonitoredItem_queuedValue *)UA_malloc(sizeof(MonitoredItem_queuedValue));
     if(!newQueueItem) {
         UA_LOG_WARNING_SESSION(server->config.logger, sub->session,
                                "Subscription %u | MonitoredItem %i | "
@@ -344,7 +344,7 @@ UA_Subscription_addRetransmissionMessage(UA_Server *server, UA_Subscription *sub
        sub->retransmissionQueueSize >= server->config.maxRetransmissionQueueSize) {
         UA_NotificationMessageEntry *lastentry =
             TAILQ_LAST(&sub->retransmissionQueue,
-			           memberstruct(UA_Subscription,UA_ListOfNotificationMessages));
+                       memberstruct(UA_Subscription,UA_ListOfNotificationMessages));
         TAILQ_REMOVE(&sub->retransmissionQueue, lastentry, listEntry);
         --sub->retransmissionQueueSize;
         UA_NotificationMessage_deleteMembers(&lastentry->message);
@@ -383,8 +383,10 @@ prepareNotificationMessage(UA_Subscription *sub, UA_NotificationMessage *message
 
     /* Allocate Notification */
     UA_DataChangeNotification *dcn = UA_DataChangeNotification_new();
-    if(!dcn)
-        goto cleanup;
+    if(!dcn) {
+        UA_NotificationMessage_deleteMembers(message);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
     UA_ExtensionObject *data = message->notificationData;
     data->encoding = UA_EXTENSIONOBJECT_DECODED;
     data->content.decoded.data = dcn;
@@ -393,8 +395,10 @@ prepareNotificationMessage(UA_Subscription *sub, UA_NotificationMessage *message
     /* Allocate array of notifications */
     dcn->monitoredItems = (UA_MonitoredItemNotification *)
         UA_Array_new(notifications, &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION]);
-    if(!dcn->monitoredItems)
-        goto cleanup;
+    if(!dcn->monitoredItems) {
+        UA_NotificationMessage_deleteMembers(message);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
     dcn->monitoredItemsSize = notifications;
 
     /* Move notifications into the response .. the point of no return */
@@ -415,10 +419,6 @@ prepareNotificationMessage(UA_Subscription *sub, UA_NotificationMessage *message
         }
     }
     return UA_STATUSCODE_GOOD;
-    
- cleanup:
-    UA_NotificationMessage_deleteMembers(message);
-    return UA_STATUSCODE_BADOUTOFMEMORY;
 }
 
 void UA_Subscription_publishCallback(UA_Server *server, UA_Subscription *sub) {
@@ -537,7 +537,7 @@ void UA_Subscription_publishCallback(UA_Server *server, UA_Subscription *sub) {
     sub->state = UA_SUBSCRIPTIONSTATE_NORMAL;
     sub->currentKeepAliveCount = 0;
     sub->currentLifetimeCount = 0;
-    
+
     /* Free the response */
     UA_Array_delete(response->results, response->resultsSize,
                     &UA_TYPES[UA_TYPES_UINT32]);

+ 106 - 72
src/ua_connection.c

@@ -9,55 +9,57 @@ void UA_Connection_deleteMembers(UA_Connection *connection) {
     UA_ByteString_deleteMembers(&connection->incompleteMessage);
 }
 
-UA_StatusCode
-UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
-                              UA_Boolean * UA_RESTRICT realloced) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-
-    /* We have a stored an incomplete chunk. Concat the received message to the end.
-     * After this block, connection->incompleteMessage is always empty. */
-    if(connection->incompleteMessage.length > 0) {
-        size_t length = connection->incompleteMessage.length + message->length;
-        UA_Byte *data = (UA_Byte*)UA_realloc(connection->incompleteMessage.data, length);
-        if(!data) {
-            retval = UA_STATUSCODE_BADOUTOFMEMORY;
-            goto cleanup;
-        }
-        memcpy(&data[connection->incompleteMessage.length], message->data, message->length);
+static UA_StatusCode
+prependIncomplete(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
+                  UA_Boolean * UA_RESTRICT realloced) {
+    UA_assert(connection->incompleteMessage.length > 0);
+
+    /* Allocate the new message buffer */
+    size_t length = connection->incompleteMessage.length + message->length;
+    UA_Byte *data = (UA_Byte*)UA_realloc(connection->incompleteMessage.data, length);
+    if(!data) {
+        UA_ByteString_deleteMembers(&connection->incompleteMessage);
         connection->releaseRecvBuffer(connection, message);
-        message->data = data;
-        message->length = length;
-        *realloced = true;
-        connection->incompleteMessage = UA_BYTESTRING_NULL;
+        return UA_STATUSCODE_BADOUTOFMEMORY;
     }
 
-    /* Loop over the chunks in the received buffer */
-    size_t complete_until = 0; /* the received complete chunks end at this point */
-    UA_Boolean garbage_end = false; /* garbage after the last complete message */
+    /* Copy / release the current message buffer */
+    memcpy(&data[connection->incompleteMessage.length], message->data, message->length);
+    connection->releaseRecvBuffer(connection, message);
+    message->length = length;
+    message->data = data;
+    connection->incompleteMessage = UA_BYTESTRING_NULL;
+    *realloced = true;
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+completeChunksUntil(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
+                    UA_Boolean *garbage_end) {
+    size_t complete_until = 0;
+
+    /* At least 8 byte needed for the header... */
     while(message->length - complete_until >= 8) {
         /* Check the message type */
         UA_UInt32 msgtype = (UA_UInt32)message->data[complete_until] +
-            ((UA_UInt32)message->data[complete_until+1] << 8) +
-            ((UA_UInt32)message->data[complete_until+2] << 16);
+                           ((UA_UInt32)message->data[complete_until+1] << 8) +
+                           ((UA_UInt32)message->data[complete_until+2] << 16);
         if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
            msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
            msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
            msgtype != ('A' + ('C' << 8) + ('K' << 16)) &&
            msgtype != ('C' + ('L' << 8) + ('O' << 16))) {
-            garbage_end = true; /* the message type is not recognized */
+            *garbage_end = true; /* the message type is not recognized */
             break;
         }
 
-        /* Decode the length of the chunk */
+        /* Decoding failed or the message size is not allowed. The remaining
+         * message is garbage. */
         UA_UInt32 chunk_length = 0;
         size_t length_pos = complete_until + 4;
-        UA_StatusCode decode_retval = UA_UInt32_decodeBinary(message, &length_pos, &chunk_length);
-
-        /* The message size is not allowed. Throw the remaining bytestring away */
-        if(decode_retval != UA_STATUSCODE_GOOD ||
-           chunk_length < 16 ||
-           chunk_length > connection->localConf.recvBufferSize) {
-            garbage_end = true;
+        if(UA_UInt32_decodeBinary(message, &length_pos, &chunk_length) != UA_STATUSCODE_GOOD ||
+           chunk_length < 16 || chunk_length > connection->localConf.recvBufferSize) {
+            *garbage_end = true;
             break;
         }
 
@@ -65,52 +67,85 @@ UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RES
         if(chunk_length + complete_until > message->length)
             break;
 
-        complete_until += chunk_length; /* Go to the next chunk */
+        /* Continue to the next chunk */
+        complete_until += chunk_length;
     }
 
-    /* Separate incomplete chunks */
-    if(complete_until != message->length) {
-        /* Garbage after the last good chunk. No need to keep a buffer */
-        if(garbage_end) {
-            if(complete_until == 0)
-                goto cleanup; /* All garbage, only happens on messages from the network layer */
-            message->length = complete_until;
-            return UA_STATUSCODE_GOOD;
-        }
+    UA_assert(complete_until <= message->length);
+    return complete_until;
+}
 
-        /* No good chunk, only an incomplete one */
-        if(complete_until == 0) {
-            if(!*realloced) {
-                retval = UA_ByteString_allocBuffer(&connection->incompleteMessage, message->length);
-                if(retval != UA_STATUSCODE_GOOD)
-                    goto cleanup;
-                memcpy(connection->incompleteMessage.data, message->data, message->length);
-                connection->releaseRecvBuffer(connection, message);
-                *realloced = true;
-            } else {
-                connection->incompleteMessage = *message;
-                *message = UA_BYTESTRING_NULL;
-            }
-            return UA_STATUSCODE_GOOD;
-        }
+static UA_StatusCode
+separateIncompleteChunk(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
+                        size_t complete_until, UA_Boolean garbage_end, UA_Boolean *realloced) {
+    UA_assert(complete_until < message->length);
 
-        /* At least one good chunk and an incomplete one */
-        size_t incomplete_length = message->length - complete_until;
-        retval = UA_ByteString_allocBuffer(&connection->incompleteMessage, incomplete_length);
-        if(retval != UA_STATUSCODE_GOOD)
-            goto cleanup;
-        memcpy(connection->incompleteMessage.data,
-               &message->data[complete_until], incomplete_length);
+    /* Garbage after the last good chunk. No need to keep an incomplete message. */
+    if(garbage_end) {
+        if(complete_until == 0) /* All garbage */
+            return UA_STATUSCODE_BADDECODINGERROR;
         message->length = complete_until;
+        return UA_STATUSCODE_GOOD;
     }
 
+    /* No good chunk, buffer the entire message */
+    if(complete_until == 0) {
+        if(!*realloced) {
+            UA_StatusCode retval =
+                UA_ByteString_allocBuffer(&connection->incompleteMessage, message->length);
+            if(retval != UA_STATUSCODE_GOOD)
+                return retval;
+            memcpy(connection->incompleteMessage.data, message->data, message->length);
+            connection->releaseRecvBuffer(connection, message);
+            *realloced = true;
+        } else {
+            connection->incompleteMessage = *message;
+            *message = UA_BYTESTRING_NULL;
+        }
+        return UA_STATUSCODE_GOOD;
+    }
+
+    /* At least one good chunk and an incomplete one */
+    size_t incomplete_length = message->length - complete_until;
+    UA_StatusCode retval =
+        UA_ByteString_allocBuffer(&connection->incompleteMessage, incomplete_length);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    memcpy(connection->incompleteMessage.data, &message->data[complete_until], incomplete_length);
+    message->length = complete_until;
     return UA_STATUSCODE_GOOD;
+}
 
- cleanup:
-    if(!*realloced)
-        connection->releaseRecvBuffer(connection, message);
-    UA_ByteString_deleteMembers(&connection->incompleteMessage);
-    return retval;
+UA_StatusCode
+UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
+                              UA_Boolean * UA_RESTRICT realloced) {
+    /* If we have a stored an incomplete chunk, prefix to the received message.
+     * After this block, connection->incompleteMessage is always empty. The
+     * message and the buffer is released if allocating the memory fails. */
+    if(connection->incompleteMessage.length > 0) {
+        UA_StatusCode retval = prependIncomplete(connection, message, realloced);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
+
+    /* Find the end of the last complete chunk */
+    UA_Boolean garbage_end = false; /* garbage after the last complete message */
+    size_t complete_until = completeChunksUntil(connection, message, &garbage_end);
+
+    /* Buffer incomplete chunk (at the end of the message) in the connection and
+     * adjust the size of the message. */
+    if(complete_until < message->length) {
+        UA_StatusCode retval = separateIncompleteChunk(connection, message, complete_until,
+                                                       garbage_end, realloced);
+        if(retval != UA_STATUSCODE_GOOD) {
+            if(*realloced)
+                UA_ByteString_deleteMembers(message);
+            else
+                connection->releaseRecvBuffer(connection, message);
+            return retval;
+        }
+    }
+    return UA_STATUSCODE_GOOD;
 }
 
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {
@@ -123,8 +158,7 @@ void UA_Connection_detachSecureChannel(UA_Connection *connection) {
 
 // TODO: Return an error code
 void
-UA_Connection_attachSecureChannel(UA_Connection *connection,
-                                  UA_SecureChannel *channel) {
+UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
     if(UA_atomic_cmpxchg((void**)&channel->connection, NULL, connection) == NULL)
         UA_atomic_xchg((void**)&connection->channel, (void*)channel);
 }

+ 8 - 0
src/ua_connection_internal.h

@@ -1,6 +1,10 @@
 #ifndef UA_CONNECTION_INTERNAL_H_
 #define UA_CONNECTION_INTERNAL_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "ua_connection.h"
 
 /**
@@ -42,4 +46,8 @@ void UA_EXPORT UA_Connection_attachSecureChannel(UA_Connection *connection, UA_S
  */
 UA_StatusCode UA_EXPORT UA_EndpointUrl_split_ptr(const char *endpointUrl, char *hostname, const char ** port, const char ** path);
 
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
 #endif /* UA_CONNECTION_INTERNAL_H_ */

+ 8 - 0
src/ua_securechannel.h

@@ -1,6 +1,10 @@
 #ifndef UA_SECURECHANNEL_H_
 #define UA_SECURECHANNEL_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "queue.h"
 #include "ua_types.h"
 #include "ua_transport_generated.h"
@@ -106,4 +110,8 @@ UA_SecureChannel_processChunks(UA_SecureChannel *channel, const UA_ByteString *c
                  ((CHANNEL)->connection ? (CHANNEL)->connection->sockfd : 0), \
                  (CHANNEL)->securityToken.channelId, ##__VA_ARGS__);
 
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
 #endif /* UA_SECURECHANNEL_H_ */

+ 8 - 0
src/ua_session.h

@@ -1,6 +1,10 @@
 #ifndef UA_SESSION_H_
 #define UA_SESSION_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "queue.h"
 #include "ua_types.h"
 #include "ua_securechannel.h"
@@ -118,4 +122,8 @@ UA_Session_getUniqueSubscriptionID(UA_Session *session);
                  UA_PRINTF_GUID_DATA(SESSION->sessionId.identifier.guid), \
                  ##__VA_ARGS__);
 
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
 #endif /* UA_SESSION_H_ */

+ 5 - 5
src/ua_types.c

@@ -15,11 +15,11 @@
 
 /* Global definition of NULL type instances. These are always zeroed out, as
  * mandated by the C/C++ standard for global values with no initializer. */
-const UA_String UA_STRING_NULL;
-const UA_ByteString UA_BYTESTRING_NULL;
-const UA_Guid UA_GUID_NULL;
-const UA_NodeId UA_NODEID_NULL;
-const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL;
+const UA_String UA_STRING_NULL = {0, NULL};
+const UA_ByteString UA_BYTESTRING_NULL = {0, NULL};
+const UA_Guid UA_GUID_NULL = {0, 0, 0, {0,0,0,0,0,0,0,0}};
+const UA_NodeId UA_NODEID_NULL = {0, UA_NODEIDTYPE_NUMERIC, {0}};
+const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL = {{0, UA_NODEIDTYPE_NUMERIC, {0}}, {0, NULL}, 0};
 
 /* TODO: The standard-defined types are ordered. See if binary search is more
  * efficient. */

+ 8 - 0
src/ua_util.h

@@ -3,6 +3,10 @@
 
 #include "ua_config.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Assert */
 #include <assert.h>
 #define UA_assert(ignore) assert(ignore)
@@ -98,4 +102,8 @@ UA_atomic_add(volatile uint32_t *addr, uint32_t increase) {
 #endif
 }
 
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
 #endif /* UA_UTIL_H_ */