Browse Source

Enable PubSub tests and static code analysis (#1833)

* enable PubSub tests and static code analysis

* changed cleanup order
andreasebner 5 years ago
parent
commit
cf8a55353f

+ 1 - 1
CMakeLists.txt

@@ -186,7 +186,7 @@ endif()
 
 option(UA_ENABLE_PUBSUB "Enable publish/subscribe (experimental)" OFF)
 mark_as_advanced(UA_ENABLE_PUBSUB)
-option(UA_ENABLE_PUBSUB_DELTAFRAMES "Enable sending of delta frames with only the changes" ON)
+option(UA_ENABLE_PUBSUB_DELTAFRAMES "Enable sending of delta frames with only the changes" OFF)
 mark_as_advanced(UA_ENABLE_PUBSUB_DELTAFRAMES)
 option(UA_ENABLE_PUBSUB_INFORMATIONMODEL "Enable PubSub information model twin" OFF)
 mark_as_advanced(UA_ENABLE_PUBSUB_INFORMATIONMODEL)

+ 2 - 0
arch/posix/CMakeLists.txt

@@ -20,6 +20,8 @@ if (${_index} GREATER -1 OR "${UA_ARCHITECTURE}" STREQUAL "posix")
           ua_architecture_append_to_library(netdb ndblib socket)
         else()
           ua_architecture_append_to_library(m)
+          #TODO - Error on first make run if pthread is included conditional?
+          ua_architecture_append_to_library(pthread)
           if(UA_ENABLE_MULTITHREADING OR UA_BUILD_UNIT_TESTS)
             ua_architecture_append_to_library(pthread)
           endif()

+ 5 - 4
arch/win32/CMakeLists.txt

@@ -10,10 +10,11 @@ if (${_index} GREATER -1 OR "${UA_ARCHITECTURE}" STREQUAL "win32")
 
     if("${UA_ARCHITECTURE}" STREQUAL "win32")
         ua_architecture_append_to_library(ws2_32)
-
-        if(UA_ENABLE_DISCOVERY_MULTICAST OR UA_ENABLE_PUBSUB)
-            ua_architecture_append_to_library(iphlpapi)
-        endif()
+        ua_architecture_append_to_library(iphlpapi)
+	#append iphlpapi permanently. Problem: PUBSUB Flag is configured after execution.        
+	#if(UA_ENABLE_DISCOVERY_MULTICAST OR UA_ENABLE_PUBSUB)
+        #    ua_architecture_append_to_library(iphlpapi)
+        #endif()
     endif()
 
     ua_include_directories(${CMAKE_CURRENT_SOURCE_DIR})

+ 1 - 1
examples/pubsub/tutorial_pubsub_subscribe.c

@@ -49,7 +49,7 @@ subscriptionPollingCallback(UA_Server *server, UA_PubSubConnection *connection)
 
     /* Decode the message */
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
-                "Message length: %zu", buffer.length);
+                "Message length: %lu", (unsigned long) buffer.length);
     UA_NetworkMessage networkMessage;
     memset(&networkMessage, 0, sizeof(UA_NetworkMessage));
     size_t currentPosition = 0;

+ 15 - 1
include/ua_server_pubsub.h

@@ -68,8 +68,22 @@ _UA_BEGIN_DECLS
  *                 |    +-----------------+
  *                 +----> UA_DataSetField |  UA_PublishedDataSet_addDataSetField
  *                      +-----------------+
+ * PubSub compile flags
+ * --------------------
+ *
+ * **UA_ENABLE_PUBSUB**
+ *  Enable the experimental OPC UA PubSub support. The option will include the PubSub UDP multicast plugin. Disabled by default.
+ * **UA_ENABLE_PUBSUB_DELTAFRAMES**
+ *  The PubSub messages differentiate between keyframe (all published values contained) and deltaframe (only changed values contained) messages.
+ *  Deltaframe messages creation consumes some additional ressources and can be disabled with this flag. Disabled by default.
+ *  Compile the human-readable name of the StatusCodes into the binary. Disabled by default.
+ * **UA_ENABLE_PUBSUB_INFORMATIONMODEL**
+ *  Enable the information model representation of the PubSub configuration. For more details take a look at the following section `PubSub Information Model Representation`. Disabled by default.
+ *
  * PubSub Information Model Representation
- * -----------
+ * ----------------------------------------
+ * .. _pubsub_informationmodel:
+ *
  * The complete PubSub configuration is available inside the information model.
  * The entry point is the node 'PublishSubscribe, located under the Server node.
  * The standard defines for PubSub no new Service set. The configuration can optionally

+ 3 - 2
plugins/ua_network_pubsub_udp.c

@@ -46,7 +46,8 @@ UA_PubSubChannelUDPMC_open(const UA_PubSubConnectionConfig *connectionConfig) {
         return NULL;
     }
     //set default values
-    memcpy(channelDataUDPMC, &(UA_PubSubChannelDataUDPMC){0, NULL, 255, UA_TRUE, UA_TRUE}, sizeof(UA_PubSubChannelDataUDPMC));
+    UA_PubSubChannelDataUDPMC defaultValues = {0, NULL, 255, UA_TRUE, UA_TRUE};
+    memcpy(channelDataUDPMC, &defaultValues, sizeof(UA_PubSubChannelDataUDPMC));
     //iterate over the given KeyValuePair paramters
     UA_String ttlParam = UA_STRING("ttl"), loopbackParam = UA_STRING("loopback"), reuseParam = UA_STRING("reuse");
     for(size_t i = 0; i < connectionConfig->connectionPropertiesSize; i++){
@@ -412,11 +413,11 @@ UA_PubSubChannelUDPMC_receive(UA_PubSubChannel *channel, UA_ByteString *message,
  */
 static UA_StatusCode
 UA_PubSubChannelUDPMC_close(UA_PubSubChannel *channel) {
-    UA_deinitialize_architecture_network();
     if(UA_close(channel->sockfd) != 0){
         UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "PubSub Connection delete failed.");
         return UA_STATUSCODE_BADINTERNALERROR;
     }
+    UA_deinitialize_architecture_network();
     //cleanup the internal NetworkLayer data
     UA_PubSubChannelDataUDPMC *networkLayerData = (UA_PubSubChannelDataUDPMC *) channel->handle;
     UA_free(networkLayerData->ai_addr);

+ 37 - 21
src/pubsub/ua_pubsub.c

@@ -260,19 +260,26 @@ UA_Server_addDataSetField(UA_Server *server, const UA_NodeId publishedDataSet,
                           const UA_DataSetFieldConfig *fieldConfig,
                           UA_NodeId *fieldIdentifier) {
     UA_StatusCode retVal = UA_STATUSCODE_GOOD;
+	UA_DataSetFieldResult result = {UA_STATUSCODE_BADINVALIDARGUMENT, {0, 0}};
     if(!fieldConfig)
-        return (UA_DataSetFieldResult) {UA_STATUSCODE_BADINVALIDARGUMENT, {0, 0}};
+        return result;
 
     UA_PublishedDataSet *currentDataSet = UA_PublishedDataSet_findPDSbyId(server, publishedDataSet);
-    if(currentDataSet == NULL)
-        return (UA_DataSetFieldResult) {UA_STATUSCODE_BADNOTFOUND, {0, 0}};
+	if(currentDataSet == NULL){
+		result.result = UA_STATUSCODE_BADNOTFOUND;
+        return result;
+	}
 
-    if(currentDataSet->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS)
-        return (UA_DataSetFieldResult) {UA_STATUSCODE_BADNOTIMPLEMENTED, {0, 0}};
+	if(currentDataSet->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS){
+		result.result = UA_STATUSCODE_BADNOTIMPLEMENTED;
+        return result;
+	}
 
     UA_DataSetField *newField = (UA_DataSetField *) UA_calloc(1, sizeof(UA_DataSetField));
-    if(!newField)
-        return (UA_DataSetFieldResult) {UA_STATUSCODE_BADINTERNALERROR, {0, 0}};
+	if(!newField){
+		result.result = UA_STATUSCODE_BADINTERNALERROR;
+        return result;
+	}
 
     UA_DataSetFieldConfig tmpFieldConfig;
     retVal |= UA_DataSetFieldConfig_copy(fieldConfig, &tmpFieldConfig);
@@ -288,22 +295,23 @@ UA_Server_addDataSetField(UA_Server *server, const UA_NodeId publishedDataSet,
     if(newField->config.field.variable.promotedField)
         currentDataSet->promotedFieldsCount++;
     currentDataSet->fieldSize++;
-    UA_DataSetFieldResult result =
-        {retVal, {currentDataSet->dataSetMetaData.configurationVersion.majorVersion,
-                  currentDataSet->dataSetMetaData.configurationVersion.minorVersion}};
+	result.result = retVal;
+	result.configurationVersion.majorVersion = currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
+	result.configurationVersion.minorVersion = currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
     return result;
 }
 
 UA_DataSetFieldResult
 UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf) {
     UA_DataSetField *currentField = UA_DataSetField_findDSFbyId(server, dsf);
-    if(!currentField)
-        return (UA_DataSetFieldResult) {UA_STATUSCODE_BADNOTFOUND, {0, 0}};
+    UA_DataSetFieldResult result = {UA_STATUSCODE_BADNOTFOUND, {0, 0}};
+	if(!currentField)
+        return result;
 
     UA_PublishedDataSet *parentPublishedDataSet =
         UA_PublishedDataSet_findPDSbyId(server, currentField->publishedDataSet);
     if(!parentPublishedDataSet)
-        return (UA_DataSetFieldResult) {UA_STATUSCODE_BADNOTFOUND, {0, 0}};
+        return result;
 
     parentPublishedDataSet->fieldSize--;
     if(currentField->config.field.variable.promotedField)
@@ -314,9 +322,9 @@ UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf) {
         UA_PubSubConfigurationVersionTimeDifference();
     UA_DataSetField_deleteMembers(currentField);
     UA_free(currentField);
-    UA_DataSetFieldResult result =
-        {UA_STATUSCODE_GOOD, {parentPublishedDataSet->dataSetMetaData.configurationVersion.majorVersion,
-                              parentPublishedDataSet->dataSetMetaData.configurationVersion.minorVersion}};
+	result.result = UA_STATUSCODE_GOOD;
+	result.configurationVersion.majorVersion = parentPublishedDataSet->dataSetMetaData.configurationVersion.majorVersion;
+	result.configurationVersion.minorVersion = parentPublishedDataSet->dataSetMetaData.configurationVersion.minorVersion;
     return result;
 }
 
@@ -990,6 +998,11 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
         UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, "Unknown encoding type.");
         return;
     }
+    UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, writerGroup->linkedConnection);
+    if(!connection){
+        UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, "Publish failed. PubSubConnection invalid.");
+        return;
+    }
     //prevent error if the maxEncapsulatedDataSetMessageCount is set to 0->1
     writerGroup->config.maxEncapsulatedDataSetMessageCount = (UA_UInt16) (writerGroup->config.maxEncapsulatedDataSetMessageCount == 0 ||
                                                                           writerGroup->config.maxEncapsulatedDataSetMessageCount > UA_BYTE_MAX
@@ -1056,6 +1069,14 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
                 (combinedNetworkMessageCount % writerGroup->config.maxEncapsulatedDataSetMessageCount) == 0 ? 0 : 1);
         networkMessageCount += combinedNetworkMessageCount;
     }
+    if(networkMessageCount < 1){
+        for(size_t i = 0; i < writerGroup->writersCount; i++){
+            UA_DataSetMessage_free(&dsmStore[i]);
+        }
+        UA_free(dsmStore);
+        return;
+    }
+
     //Alloc memory for the NetworkMessages on the stack
     UA_STACKARRAY(UA_NetworkMessage, nmStore, networkMessageCount);
     memset(nmStore, 0, networkMessageCount * sizeof(UA_NetworkMessage));
@@ -1093,11 +1114,6 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
             nmStore->payload.dataSetPayload.sizes = &dsmSizes[currentDSMPosition];
             nmStore->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = &dsWriterIds[currentDSMPosition];
         }
-        UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, writerGroup->linkedConnection);
-        if(!connection){
-            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, "Publish failed. PubSubConnection invalid.");
-            return;
-        }
         //send the prepared messages
         UA_ByteString buf;
         size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nmStore[i]);

+ 17 - 12
src/pubsub/ua_pubsub_manager.c

@@ -139,15 +139,16 @@ UA_Server_removePubSubConnection(UA_Server *server, const UA_NodeId connection)
 UA_AddPublishedDataSetResult
 UA_Server_addPublishedDataSet(UA_Server *server, const UA_PublishedDataSetConfig *publishedDataSetConfig,
                               UA_NodeId *pdsIdentifier) {
+    UA_AddPublishedDataSetResult result = {UA_STATUSCODE_BADINVALIDARGUMENT, 0, NULL, {0, 0}};
     if(!publishedDataSetConfig){
         UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
                      "PublishedDataSet creation failed. No config passed in.");
-        return (UA_AddPublishedDataSetResult) {UA_STATUSCODE_BADINVALIDARGUMENT, 0, NULL, {0, 0}};
+        return result;
     }
     if(publishedDataSetConfig->publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS){
         UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
                      "PublishedDataSet creation failed. Unsupported PublishedDataSet type.");
-        return (UA_AddPublishedDataSetResult) {UA_STATUSCODE_BADINVALIDARGUMENT, 0, NULL, {0, 0}};
+        return result;
     }
     //deep copy the given connection config
     UA_PublishedDataSetConfig tmpPublishedDataSetConfig;
@@ -155,7 +156,8 @@ UA_Server_addPublishedDataSet(UA_Server *server, const UA_PublishedDataSetConfig
     if(UA_PublishedDataSetConfig_copy(publishedDataSetConfig, &tmpPublishedDataSetConfig) != UA_STATUSCODE_GOOD){
         UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
                      "PublishedDataSet creation failed. Configuration copy failed.");
-        return (UA_AddPublishedDataSetResult) {UA_STATUSCODE_BADINTERNALERROR, 0, NULL, {0, 0}};
+		result.addResult = UA_STATUSCODE_BADINTERNALERROR;
+        return result;
     }
     //create new PDS and add to UA_PubSubManager
     UA_PublishedDataSet *newPubSubDataSetField = (UA_PublishedDataSet *)
@@ -165,10 +167,11 @@ UA_Server_addPublishedDataSet(UA_Server *server, const UA_PublishedDataSetConfig
         UA_PublishedDataSetConfig_deleteMembers(&tmpPublishedDataSetConfig);
         UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
                      "PublishedDataSet creation failed. Out of Memory.");
-        return (UA_AddPublishedDataSetResult) {UA_STATUSCODE_BADOUTOFMEMORY, 0, NULL, {0, 0}};
+		result.addResult = UA_STATUSCODE_BADOUTOFMEMORY;
+		return result;
     }
     server->pubSubManager.publishedDataSets = newPubSubDataSetField;
-    UA_PublishedDataSet *newPubSubDataSet = &server->pubSubManager.publishedDataSets[server->pubSubManager.publishedDataSetsSize];
+    UA_PublishedDataSet *newPubSubDataSet = &server->pubSubManager.publishedDataSets[(server->pubSubManager.publishedDataSetsSize)];
     memset(newPubSubDataSet, 0, sizeof(UA_PublishedDataSet));
     LIST_INIT(&newPubSubDataSet->fields);
     //workaround - fixing issue with queue.h and realloc.
@@ -187,9 +190,11 @@ UA_Server_addPublishedDataSet(UA_Server *server, const UA_PublishedDataSetConfig
         UA_NodeId_copy(&newPubSubDataSet->identifier, pdsIdentifier);
     }
     server->pubSubManager.publishedDataSetsSize++;
-    UA_AddPublishedDataSetResult result = {UA_STATUSCODE_GOOD, 0, NULL,
-                                                 {UA_PubSubConfigurationVersionTimeDifference(),
-                                                  UA_PubSubConfigurationVersionTimeDifference()}};
+	result.addResult = UA_STATUSCODE_GOOD;
+	result.fieldAddResults = NULL;
+	result.fieldAddResultsSize = 0;
+	result.configurationVersion.majorVersion = UA_PubSubConfigurationVersionTimeDifference();
+	result.configurationVersion.minorVersion = UA_PubSubConfigurationVersionTimeDifference();
 #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
     addPublishedDataItemsRepresentation(server, newPubSubDataSet);
 #endif
@@ -275,6 +280,10 @@ UA_PubSubManager_generateUniqueNodeId(UA_Server *server, UA_NodeId *nodeId) {
 void
 UA_PubSubManager_delete(UA_Server *server, UA_PubSubManager *pubSubManager) {
     UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER, "PubSub cleanup was called.");
+    //free the currently configured transport layers
+    for(size_t i = 0; i < server->config.pubsubTransportLayersSize; i++){
+        UA_free(&server->config.pubsubTransportLayers[i]);
+    }
     //remove Connections and WriterGroups
     while(pubSubManager->connectionsSize > 0){
         UA_Server_removePubSubConnection(server, pubSubManager->connections[pubSubManager->connectionsSize-1].identifier);
@@ -282,10 +291,6 @@ UA_PubSubManager_delete(UA_Server *server, UA_PubSubManager *pubSubManager) {
     while(pubSubManager->publishedDataSetsSize > 0){
         UA_Server_removePublishedDataSet(server, pubSubManager->publishedDataSets[pubSubManager->publishedDataSetsSize-1].identifier);
     }
-    //free the currently configured transport layers
-    for(size_t i = 0; i < server->config.pubsubTransportLayersSize; i++){
-        UA_free(&server->config.pubsubTransportLayers[i]);
-    }
 }
 
 /***********************************/

+ 17 - 5
src/pubsub/ua_pubsub_ns0.c

@@ -76,12 +76,13 @@ onRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
     UA_Variant value;
     UA_Variant_init(&value);
     UA_NodeId myNodeId;
+	UA_WriterGroup *writerGroup = NULL;
     switch(((UA_NodePropertyContext *) nodeContext)->parentCalssifier){
         case UA_NS0ID_PUBSUBCONNECTIONTYPE:
             break;
         case UA_NS0ID_WRITERGROUPTYPE:
             myNodeId = ((UA_NodePropertyContext *) nodeContext)->parentNodeId;
-            UA_WriterGroup *writerGroup = UA_WriterGroup_findWGbyId(server, myNodeId);
+            writerGroup = UA_WriterGroup_findWGbyId(server, myNodeId);
             if(!writerGroup)
                 return;
             switch(((UA_NodePropertyContext *) nodeContext)->elementClassiefier){
@@ -104,12 +105,13 @@ onWrite(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
         const UA_NumericRange *range, const UA_DataValue *data){
     UA_Variant value;
     UA_NodeId myNodeId;
+	UA_WriterGroup *writerGroup = NULL;
     switch(((UA_NodePropertyContext *) nodeContext)->parentCalssifier){
         case UA_NS0ID_PUBSUBCONNECTIONTYPE:
             break;
         case UA_NS0ID_WRITERGROUPTYPE:
             myNodeId = ((UA_NodePropertyContext *) nodeContext)->parentNodeId;
-            UA_WriterGroup *writerGroup = UA_WriterGroup_findWGbyId(server, myNodeId);
+            writerGroup = UA_WriterGroup_findWGbyId(server, myNodeId);
             UA_WriterGroupConfig writerGroupConfig;
             memset(&writerGroupConfig, 0, sizeof(writerGroupConfig));
             if(!writerGroup)
@@ -151,8 +153,15 @@ addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connec
     connectionName[connection->config->name.length] = '\0';
     //This code block must use a lock
     UA_Nodestore_remove(server, &connection->identifier);
-    retVal |= addPubSubObjectNode(server, connectionName, connection->identifier.identifier.numeric, UA_NS0ID_PUBLISHSUBSCRIBE,
-                            UA_NS0ID_HASPUBSUBCONNECTION, UA_NS0ID_PUBSUBCONNECTIONTYPE);
+    UA_NodeId pubSubConnectionNodeId;
+    UA_ObjectAttributes attr = UA_ObjectAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("de-DE", connectionName);
+    retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(0, connection->identifier.identifier.numeric),
+    UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPUBSUBCONNECTION),
+    UA_QUALIFIEDNAME(0, connectionName), UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE), (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL, &pubSubConnectionNodeId);
+    addPubSubObjectNode(server, "Address", connection->identifier.identifier.numeric+1, pubSubConnectionNodeId.identifier.numeric,  UA_NS0ID_HASCOMPONENT, UA_NS0ID_NETWORKADDRESSURLTYPE);
+    UA_Server_addNode_finish(server, pubSubConnectionNodeId);
+
     //End lock zone
     UA_NodeId addressNode, urlNode, interfaceNode;
     addressNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Address"),
@@ -241,7 +250,10 @@ addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup){
     publishingIntervalContext->parentNodeId = writerGroup->identifier;
     publishingIntervalContext->parentCalssifier = UA_NS0ID_WRITERGROUPTYPE;
     publishingIntervalContext->elementClassiefier = UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL;
-    retVal |= addVariableValueSource(server,(UA_ValueCallback) {onRead, onWrite}, publishingIntervalNode, publishingIntervalContext);
+    UA_ValueCallback valueCallback;
+    valueCallback.onRead = onRead;
+    valueCallback.onWrite = onWrite;
+    retVal |= addVariableValueSource(server, valueCallback, publishingIntervalNode, publishingIntervalContext);
     UA_Server_writeAccessLevel(server, publishingIntervalNode, (UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE));
 
     priorityNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Priority"),

+ 5 - 5
tests/CMakeLists.txt

@@ -191,15 +191,15 @@ if(UA_ENABLE_PUBSUB)
     add_executable(check_pubsub_encoding pubsub/check_pubsub_encoding.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-testplugins>)
     target_link_libraries(check_pubsub_encoding ${LIBS})
     add_test_valgrind(pubsub_encoding ${TESTS_BINARY_DIR}/check_pubsub_encoding)
-    add_executable(check_pubsub_connection_udp pubsub/check_pubsub_connection_udp.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
-    target_link_libraries(check_pubsub_connection_udp ${LIBS})
-    add_test(NAME check_pubsub_connection_udp COMMAND check_pubsub_connection_udp)
     add_executable(check_pubsub_pds pubsub/check_pubsub_pds.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
     target_link_libraries(check_pubsub_pds ${LIBS})
-    add_test(check_pubsub_pds ${TESTS_BINARY_DIR}/check_pubsub_pds)
+    add_test_valgrind(check_pubsub_pds ${TESTS_BINARY_DIR}/check_pubsub_pds)
+    add_executable(check_pubsub_connection_udp pubsub/check_pubsub_connection_udp.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
+    target_link_libraries(check_pubsub_connection_udp ${LIBS})
+    add_test_valgrind(check_pubsub_connection_udp ${TESTS_BINARY_DIR}/check_pubsub_connection_udp)
     add_executable(check_pubsub_publish pubsub/check_pubsub_publish.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
     target_link_libraries(check_pubsub_publish ${LIBS})
-    add_test(check_pubsub_publish ${TESTS_BINARY_DIR}/check_pubsub_publish)
+    add_test_valgrind(check_pubsub_publish ${TESTS_BINARY_DIR}/check_pubsub_publish)
     if(UA_ENABLE_PUBSUB_INFORMATIONMODEL)
         add_executable(check_pubsub_informationmodel pubsub/check_pubsub_informationmodel.c $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
         target_link_libraries(check_pubsub_informationmodel ${LIBS})

+ 15 - 0
tools/appveyor/build.ps1

@@ -79,6 +79,20 @@ try {
     cd ..
     Remove-Item -Path build -Recurse -Force
 
+    Write-Host -ForegroundColor Green "`n###################################################################"
+    Write-Host -ForegroundColor Green "`n##### Testing $env:CC_NAME with PubSub #####`n"
+    New-Item -ItemType directory -Path "build"
+    cd build
+    & cmake -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_ENABLE_PUBSUB:BOOL=ON -DUA_ENABLE_PUBSUB_INFORMATIONMODEL:BOOL=ON `
+    -DUA_ENABLE_PUBSUB_DELTAFRAMES:BOOL=ON  -DUA_COMPILE_AS_CXX:BOOL=$env:FORCE_CXX -G"$env:CC_NAME"  ..
+    Invoke-Expression $make_cmd
+    if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) {
+        Write-Host -ForegroundColor Red "`n`n*** Make failed. Exiting ... ***"
+        exit $LASTEXITCODE
+    }
+    cd ..
+    Remove-Item -Path build -Recurse -Force
+
     Write-Host -ForegroundColor Green "`n###################################################################"
     Write-Host -ForegroundColor Green "`n##### Testing $env:CC_NAME with amalgamation #####`n"
     New-Item -ItemType directory -Path "build"
@@ -141,6 +155,7 @@ try {
         cd build
         & cmake $vcpkg_toolchain $vcpkg_triplet -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=OFF -DUA_ENABLE_DISCOVERY=ON `
             -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_ENABLE_ENCRYPTION:BOOL=$build_encryption -DUA_BUILD_UNIT_TESTS=ON `
+             -DUA_ENABLE_PUBSUB:BOOL=ON -DUA_ENABLE_PUBSUB_INFORMATIONMODEL:BOOL=ON -DUA_ENABLE_PUBSUB_DELTAFRAMES:BOOL=ON `
             -DUA_ENABLE_UNIT_TESTS_MEMCHECK=ON -DCHECK_PREFIX=c:\check -DUA_COMPILE_AS_CXX:BOOL=$env:FORCE_CXX -G"$env:CC_NAME" ..
         Invoke-Expression $make_cmd
         if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) {

+ 1 - 1
tools/schema/Opc.Ua.NodeSet2.PubSubMinimal.xml

@@ -780,7 +780,7 @@
     <DisplayName>Address</DisplayName>
     <References>
       <Reference ReferenceType="HasComponent">i=17202</Reference>
-      <Reference ReferenceType="HasTypeDefinition">i=21147</Reference>
+      <Reference ReferenceType="HasTypeDefinition">i=21145</Reference>
       <Reference ReferenceType="HasModellingRule">i=78</Reference>
       <Reference ReferenceType="HasComponent" IsForward="false">i=14209</Reference>
     </References>

+ 12 - 3
tools/travis/travis_linux_script.sh

@@ -66,6 +66,15 @@ if [ $ANALYZE = "true" ]; then
           make -j
         cd .. && rm build -rf
 
+        mkdir -p build
+        cd build
+        scan-build-6.0 cmake -DUA_ENABLE_PUBSUB=ON -DUA_ENABLE_PUBSUB_DELTAFRAMES=ON -DUA_ENABLE_PUBSUB_INFORMATIONMODEL=ON ..
+        scan-build-6.0 -enable-checker security.FloatLoopCounter \
+          -enable-checker security.insecureAPI.UncheckedReturn \
+          --status-bugs -v \
+          make -j
+        cd .. && rm build -rf
+
         mkdir -p build
         cd build
         scan-build-6.0 cmake -DUA_ENABLE_AMALGAMATION=ON ..
@@ -239,9 +248,9 @@ else
     mkdir -p build && cd build
     # Valgrind cannot handle the full NS0 because the generated file is too big. Thus run NS0 full without valgrind
     cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/$PYTHON -DUA_NAMESPACE_ZERO=FULL \
-    -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_PUBSUB=ON -DUA_ENABLE_ENCRYPTION=ON -DUA_ENABLE_DISCOVERY=ON \
+    -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_PUBSUB=ON -DUA_ENABLE_PUBSUB_DELTAFRAMES=ON -DUA_ENABLE_PUBSUB_INFORMATIONMODEL=ON -DUA_ENABLE_ENCRYPTION=ON -DUA_ENABLE_DISCOVERY=ON \
     -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=OFF \
-    -DUA_ENABLE_UNIT_TESTS_MEMCHECK=OFF -DUA_ENABLE_SUBSCRIPTIONS_EVENTS=ON ..
+    -DUA_ENABLE_UNIT_TESTS_MEMCHECK=OFF -DUA_ENABLE_SUBSCRIPTIONS=ON -DUA_ENABLE_SUBSCRIPTIONS_EVENTS=ON ..
     make -j && make test ARGS="-V"
     if [ $? -ne 0 ] ; then exit 1 ; fi
     cd .. && rm build -rf
@@ -251,7 +260,7 @@ else
         echo -e "\r\n== Unit tests (minimal NS0) ==" && echo -en 'travis_fold:start:script.build.unit_test_ns0_minimal\\r'
         mkdir -p build && cd build
         cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/$PYTHON \
-        -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_PUBSUB=ON -DUA_ENABLE_ENCRYPTION=ON -DUA_ENABLE_DISCOVERY=ON \
+        -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_PUBSUB=ON -DUA_ENABLE_PUBSUB_DELTAFRAMES=ON -DUA_ENABLE_PUBSUB_INFORMATIONMODEL=ON -DUA_ENABLE_ENCRYPTION=ON -DUA_ENABLE_DISCOVERY=ON \
         -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=ON \
         -DUA_ENABLE_UNIT_TESTS_MEMCHECK=ON ..
         make -j && make test ARGS="-V"