Quellcode durchsuchen

Merge branch 'master' into cleanup_build

Julius Pfrommer vor 9 Jahren
Ursprung
Commit
b04d6f867c

+ 7 - 7
.travis.yml

@@ -25,15 +25,15 @@ matrix:
     - os: osx
       compiler: gcc
 before_install:
-- "if [ ${TRAVIS_OS_NAME} == 'linux' ]; then . ./tools/travis_linux_before_install.sh; fi"
-- "if [ ${TRAVIS_OS_NAME} == 'osx' ]; then . ./tools/travis_osx_before_install.sh; fi"
+- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis_linux_before_install.sh; fi
+- if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis_osx_before_install.sh; fi
 script:
-- "if [ ${TRAVIS_OS_NAME} == 'linux' ]; then . ./tools/travis_linux_script.sh; fi"
-- "if [ ${TRAVIS_OS_NAME} == 'osx' ]; then . ./tools/travis_osx_script.sh; fi"
+- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis_linux_script.sh; fi
+- if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis_osx_script.sh; fi
 after_success:
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master") ]]; then ./tools/.deployGH_doc.sh; fi
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" ) ]]; then ./tools/.deployGH_release.sh; fi
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master") ]]; then ./tools/.coverity.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master" && ${TRAVIS_PULL_REQUEST} == "false" ) ]]; then sh ./tools/travis_push_doc.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master" && ${TRAVIS_PULL_REQUEST} == "false" ) ]]; then sh ./tools/travis_push_coverity.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" ) ]]; then sh ./tools/travis_push_release.sh; fi
 before_deploy:
 - rm build -rf && mkdir -p build && cd build
 - echo "Cross compile release build for Raspberry Pi"

+ 5 - 7
CMakeLists.txt

@@ -494,16 +494,14 @@ if(UA_BUILD_EXAMPLES)
 	endif()
 endif()
 
+# build documentation
 if(UA_BUILD_DOCUMENTATION)
     find_package(Sphinx REQUIRED)
-    configure_file(${PROJECT_SOURCE_DIR}/doc/conf.py ${PROJECT_BINARY_DIR}/conf.py @ONLY)
-    add_custom_target(latex ${SPHINX_EXECUTABLE}
-      -b latex -c "${PROJECT_BINARY_DIR}"
-      "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc/sphinx"
+    add_custom_target(doc_latex ${SPHINX_EXECUTABLE}
+      -b latex -c "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc_latex"
       COMMENT "Building LaTeX sources for documentation with Sphinx")
     add_custom_target(doc ${SPHINX_EXECUTABLE}
-      -b html -c "${PROJECT_BINARY_DIR}"
-      "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc/sphinx"
-      COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/doc/open62541_html.png" "${PROJECT_BINARY_DIR}/doc/sphinx/_static/"
+      -b html -c "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc"
+      COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/doc/open62541_html.png" "${PROJECT_BINARY_DIR}/doc/_static/"
       COMMENT "Building HTML documentation with Sphinx")
 endif()

Datei-Diff unterdrückt, da er zu groß ist
+ 11 - 11
README.md


+ 2 - 6
doc/conf.py

@@ -29,11 +29,7 @@ import shlex
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = ['breathe']
-
-breathe_projects = { "open62541-breathe": "doc/xml/" }
-breathe_default_project = "open62541-breathe"
-breathe_domain_by_extension = {"h" : "c", "c" : "c"}
+extensions = []
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -232,7 +228,7 @@ latex_documents = [
 
 # The name of an image file (relative to this directory) to place at the top of
 # the title page.
-latex_logo = "doc/open62541.png"
+latex_logo = "open62541.png"
 
 # For "manual" documents, if this is true, then toplevel headings are parts,
 # not chapters.

+ 1 - 1
doc/tutorial_server_firstSteps.rst

@@ -292,7 +292,7 @@ If you build your stack with the above two options, you will enable the example
 Unfortunately, these examples include just about everything the stack can do... which makes them rather bad examples for newcomers seeking an easy introduction. They are also dynamically configured by the CMake options, so they might be a bit more difficult to read. Non the less you can find any of the concepts demonstrated here in these examples as well and you can build them like so (and this is what you will see when you run them)::
 
    :open62541/build> make clean
-   :open62541/build> cmake -BUILD_EXAMPLECLIENT=On -BUILD_EXAMPLESERVER=On ../
+   :open62541/build> cmake -DBUILD_EXAMPLECLIENT=On -DBUILD_EXAMPLESERVER=On ../
    :open62541/build> make
    :open62541/build> ./server &
    [07/28/2015 21:42:07.977.352] info/communication        Listening on opc.tcp://Cassandra:16664

+ 1 - 1
examples/client.c

@@ -72,7 +72,7 @@ int main(int argc, char *argv[]) {
     UA_NodeId monitorThis = UA_NODEID_STRING(1, "the.answer");
     UA_UInt32 monId;
     UA_Client_Subscriptions_addMonitoredItem(client, subId, monitorThis,
-                                             UA_ATTRIBUTEID_VALUE, &handler_TheAnswerChanged, &monId);
+                                             UA_ATTRIBUTEID_VALUE, &handler_TheAnswerChanged, NULL, &monId);
     if (monId)
         printf("Monitoring 'the.answer', id %u\n", subId);
     

+ 3 - 2
examples/networklayer_tcp.c

@@ -117,10 +117,11 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
         UA_ByteString_deleteMembers(response);
 #ifdef _WIN32
         const int last_error = WSAGetLastError();
-        if(last_error == WSAEINTR || last_error == WSAEWOULDBLOCK)
+        #define TEST_RETRY (last_error == WSAEINTR || last_error == WSAEWOULDBLOCK)
 #else
-		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
+        #define TEST_RETRY (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
 #endif
+        if (TEST_RETRY)
             return UA_STATUSCODE_GOOD; /* retry */
         else {
             socket_close(connection);

+ 1 - 1
examples/server.c

@@ -414,7 +414,7 @@ int main(int argc, char** argv) {
   
     // Some easy localization
     UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("de_DE", "Objekte");
-    UA_Server_writeDisplayNameAttribute(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
+    UA_Server_writeDisplayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
   
     //start server
     UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false

+ 5 - 4
examples/server_method.c

@@ -19,8 +19,9 @@ UA_Boolean running = UA_TRUE;
 UA_Logger logger = Logger_Stdout;
 
 static UA_StatusCode
-helloWorldMethod(const UA_NodeId objectId, const UA_Variant *input,
-                 UA_Variant *output, void *handle) {
+
+helloWorldMethod(void *handle, const UA_NodeId objectId, size_t inputSize, const UA_Variant *input,
+                 size_t outputSize, UA_Variant *output) {
         UA_String *inputStr = (UA_String*)input->data;
         UA_String tmp = UA_STRING_ALLOC("Hello ");
         if(inputStr->length > 0) {
@@ -35,8 +36,8 @@ helloWorldMethod(const UA_NodeId objectId, const UA_Variant *input,
 } 
 
 static UA_StatusCode
-IncInt32ArrayValuesMethod(const UA_NodeId objectId, const UA_Variant *input,
-                          UA_Variant *output, void *handle) {
+IncInt32ArrayValuesMethod(void *handle, const UA_NodeId objectId, size_t inputSize, const UA_Variant *input, size_t outputSize, 
+                          UA_Variant *output) {
 	UA_Variant_setArrayCopy(output, input->data, 5, &UA_TYPES[UA_TYPES_INT32]);
 	for(size_t i = 0; i< input->arrayLength; i++)
 		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 1;

+ 2 - 1
include/ua_client_highlevel.h

@@ -280,7 +280,8 @@ void UA_EXPORT UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *cli
 UA_StatusCode UA_EXPORT
 UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                          UA_NodeId nodeId, UA_UInt32 attributeID,
-                                         void *handlingFunction, UA_UInt32 *newMonitoredItemId);
+                                         void *handlingFunction, void *handlingContext,
+                                         UA_UInt32 *newMonitoredItemId);
 
 UA_StatusCode UA_EXPORT
 UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,

+ 81 - 65
include/ua_server.h

@@ -349,13 +349,13 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 /* Write Node Attributes */
 /*************************/
 
-/* The following node attributes cannot be changed once the node is created
+/* The following node attributes cannot be written
    - NodeClass
    - NodeId
    - Symmetric
    - ContainsNoLoop
    
-   The following attributes cannot be written, as there is no "user" in the server
+   The following attributes cannot be written from the server, as there is no "user" in the server
    - UserWriteMask
    - UserAccessLevel
    - UserExecutable
@@ -371,51 +371,52 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 
 /* Don't use this function. There are typed versions with no additional overhead. */
 UA_StatusCode UA_EXPORT
-__UA_Server_writeAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_AttributeId attributeId, const UA_DataType *type, const void *value);
+__UA_Server_write(UA_Server *server, const UA_NodeId *nodeId, const UA_AttributeId attributeId,
+                  const UA_DataType *type, const void *value);
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeBrowseNameAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName); }
+UA_Server_writeBrowseName(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME, &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeDisplayNameAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText displayName) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName); }
+UA_Server_writeDisplayName(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText displayName) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeDescriptionAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText description) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description); }
+UA_Server_writeDescription(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText description) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeWriteMaskAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 writeMask) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_WRITEMASK, &UA_TYPES[UA_TYPES_UINT32], &writeMask); }
+UA_Server_writeWriteMask(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 writeMask) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK, &UA_TYPES[UA_TYPES_UINT32], &writeMask); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeIsAbstractAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Boolean isAbstract) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT, &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract); }
+UA_Server_writeIsAbstract(UA_Server *server, const UA_NodeId nodeId, const UA_Boolean isAbstract) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeInverseNameAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText inverseName) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName); }
+UA_Server_writeInverseName(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText inverseName) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeEventNotifierAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Byte eventNotifier) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, &UA_TYPES[UA_TYPES_BYTE], &eventNotifier); }
+UA_Server_writeEventNotifier(UA_Server *server, const UA_NodeId nodeId, const UA_Byte eventNotifier) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, &UA_TYPES[UA_TYPES_BYTE], &eventNotifier); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeValueAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Variant value) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); }
+UA_Server_writeValue(UA_Server *server, const UA_NodeId nodeId, const UA_Variant value) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeAccessLevelAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 accessLevel) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, &UA_TYPES[UA_TYPES_UINT32], &accessLevel); }
+UA_Server_writeAccessLevel(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 accessLevel) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, &UA_TYPES[UA_TYPES_UINT32], &accessLevel); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeMinimumSamplingIntervalAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Double miniumSamplingInterval) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, &UA_TYPES[UA_TYPES_DOUBLE], &miniumSamplingInterval); }
+UA_Server_writeMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId, const UA_Double miniumSamplingInterval) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, &UA_TYPES[UA_TYPES_DOUBLE], &miniumSamplingInterval); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeExecutableAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Boolean executable) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE, &UA_TYPES[UA_TYPES_BOOLEAN], &executable); }
+UA_Server_writeExecutable(UA_Server *server, const UA_NodeId nodeId, const UA_Boolean executable) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, &UA_TYPES[UA_TYPES_BOOLEAN], &executable); }
 
 /************************/
 /* Read Node Attributes */
@@ -429,84 +430,99 @@ UA_Server_writeExecutableAttribute(UA_Server *server, const UA_NodeId nodeId, co
 
 /* Don't use this function. There are typed versions for every supported attribute. */
 UA_StatusCode UA_EXPORT
-__UA_Server_readAttribute(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void *v);
+__UA_Server_read(UA_Server *server, const UA_NodeId *nodeId, UA_AttributeId attributeId, void *v);
   
 static UA_INLINE UA_StatusCode
-UA_Server_readNodeIdAttribute(UA_Server *server, UA_NodeId nodeId, UA_NodeId *outNodeId) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); }
+UA_Server_readNodeId(UA_Server *server, const UA_NodeId nodeId, UA_NodeId *outNodeId) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readNodeClassAttribute(UA_Server *server, UA_NodeId nodeId, UA_NodeClass *outNodeClass) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_NODECLASS, outNodeClass); }
+UA_Server_readNodeClass(UA_Server *server, const UA_NodeId nodeId, UA_NodeClass *outNodeClass) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODECLASS, outNodeClass); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readBrowseNameAttribute(UA_Server *server, UA_NodeId nodeId, UA_QualifiedName *outBrowseName) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, outBrowseName); }
+UA_Server_readBrowseName(UA_Server *server, const UA_NodeId nodeId, UA_QualifiedName *outBrowseName) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME, outBrowseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readDisplayNameAttribute(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDisplayName) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME, outDisplayName); }
+UA_Server_readDisplayName(UA_Server *server, const UA_NodeId nodeId, UA_LocalizedText *outDisplayName) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, outDisplayName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readDescriptionAttribute(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDescription) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION, outDescription); }
+UA_Server_readDescription(UA_Server *server, const UA_NodeId nodeId, UA_LocalizedText *outDescription) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, outDescription); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readWriteMaskAttribute(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outWriteMask) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_WRITEMASK, outWriteMask); }
+UA_Server_readWriteMask(UA_Server *server, const UA_NodeId nodeId, UA_UInt32 *outWriteMask) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK, outWriteMask); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readIsAbstractAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outIsAbstract) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT, outIsAbstract); }
+UA_Server_readIsAbstract(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outIsAbstract) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, outIsAbstract); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readSymmetricAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outSymmetric) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_SYMMETRIC, outSymmetric); }
+UA_Server_readSymmetric(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outSymmetric) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, outSymmetric); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readInverseNameAttribute(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outInverseName) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME, outInverseName); }
+UA_Server_readInverseName(UA_Server *server, const UA_NodeId nodeId, UA_LocalizedText *outInverseName) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME, outInverseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readContainsNoLoopAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outContainsNoLoops) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, outContainsNoLoops); }
+UA_Server_readContainsNoLoop(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outContainsNoLoops) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, outContainsNoLoops); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readEventNotifierAttribute(UA_Server *server, UA_NodeId nodeId, UA_Byte *outEventNotifier) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, outEventNotifier); }
+UA_Server_readEventNotifier(UA_Server *server, const UA_NodeId nodeId, UA_Byte *outEventNotifier) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, outEventNotifier); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readValueAttribute(UA_Server *server, UA_NodeId nodeId, UA_Variant *outValue) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, outValue); }
+UA_Server_readValue(UA_Server *server, const UA_NodeId nodeId, UA_Variant *outValue) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUE, outValue); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readDataTypeAttribute(UA_Server *server, UA_NodeId nodeId, UA_NodeId *outDataType) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_DATATYPE, outDataType); }
+UA_Server_readDataType(UA_Server *server, const UA_NodeId nodeId, UA_NodeId *outDataType) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DATATYPE, outDataType); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readValueRankAttribute(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outValueRank) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_VALUERANK, outValueRank); }
+UA_Server_readValueRank(UA_Server *server, const UA_NodeId nodeId, UA_Int32 *outValueRank) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUERANK, outValueRank); }
 
-// todo: fetch an array with a length field
+/* Returns a variant with an int32 array */
 static UA_INLINE UA_StatusCode
-UA_Server_readArrayDimensionsAttribute(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outArrayDimensions) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, outArrayDimensions); }
+UA_Server_readArrayDimensions(UA_Server *server, const UA_NodeId nodeId, UA_Variant *outArrayDimensions) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, outArrayDimensions); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readAccessLevelAttribute(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outAccessLevel) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, outAccessLevel); }
+UA_Server_readAccessLevel(UA_Server *server, const UA_NodeId nodeId, UA_UInt32 *outAccessLevel) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, outAccessLevel); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readMinimumSamplingIntervalAttribute(UA_Server *server, UA_NodeId nodeId, UA_Double *outMinimumSamplingInterval) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, outMinimumSamplingInterval); }
+UA_Server_readMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId, UA_Double *outMinimumSamplingInterval) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, outMinimumSamplingInterval); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readHistorizingAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outHistorizing) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_HISTORIZING, outHistorizing); }
+UA_Server_readHistorizing(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outHistorizing) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_HISTORIZING, outHistorizing); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readExecutableAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outExecutable) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE, outExecutable); }
+UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outExecutable) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, outExecutable); }
+
+/****************/
+/* Browse Nodes */
+/****************/
+
+UA_BrowseResult UA_EXPORT UA_Server_browse(UA_Server *server, UA_UInt32 maxrefs, const UA_BrowseDescription *descr);
+UA_BrowseResult UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint, const UA_ByteString *continuationPoint);
+
+/***************/
+/* Call Method */
+/***************/
+
+#ifdef ENABLE_METHODCALLS
+UA_CallMethodResult UA_EXPORT UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
+#endif
 
 #ifdef __cplusplus
 }

+ 2 - 3
include/ua_types.h

@@ -162,8 +162,7 @@ UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2)
     return UA_String_equal((const UA_String*)string1, (const UA_String*)string2); }
 
 /* Allocates memory of size length for the bytestring. The content is not set to zero. */
-UA_StatusCode UA_EXPORT
-UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+UA_StatusCode UA_EXPORT UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length);
 
 UA_EXPORT extern const UA_ByteString UA_BYTESTRING_NULL;
 
@@ -560,7 +559,7 @@ static UA_INLINE void UA_init(void *p, const UA_DataType *type) {
  * @return Indicates whether the operation succeeded or returns an error code
  */
 UA_StatusCode UA_EXPORT
-UA_copy(const void *src, void *dst, const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+UA_copy(const void *src, void *dst, const UA_DataType *type);
 
 /**
  * Deletes the dynamically assigned content of a variable (e.g. a member-array).

+ 6 - 8
src/client/ua_client.c

@@ -201,12 +201,12 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
         UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to renew the SecureChannel");
     } else {
         opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
-        UA_ByteString_init(&client->channel.clientNonce);
-        UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce);
-        opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
         UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to open a SecureChannel");
     }
 
+    UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce);
+    opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
+
     UA_ByteString message;
     UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message);
     if(retval != UA_STATUSCODE_GOOD) {
@@ -288,15 +288,13 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     if(retval != UA_STATUSCODE_GOOD)
         UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL,
                      "SecureChannel could not be opened / renewed");
-    else if(!renew) {
+    else {
         UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel.securityToken);
         /* if the handshake is repeated, replace the old nonce */
         UA_ByteString_deleteMembers(&client->channel.serverNonce);
         UA_ByteString_copy(&response.serverNonce, &client->channel.serverNonce);
-        UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel opened");
-    } else
-        UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel renewed");
-
+        UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel opened/renewed");
+    }
     UA_OpenSecureChannelResponse_deleteMembers(&response);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
     return retval;

+ 4 - 2
src/client/ua_client_highlevel_subscriptions.c

@@ -91,7 +91,8 @@ UA_StatusCode UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscr
 UA_StatusCode
 UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                          UA_NodeId nodeId, UA_UInt32 attributeID,
-                                         void *handlingFunction, UA_UInt32 *newMonitoredItemId) {
+                                         void *handlingFunction, void *handlingContext,
+                                         UA_UInt32 *newMonitoredItemId) {
     UA_Client_Subscription *sub;
     LIST_FOREACH(sub, &client->subscriptions, listEntry) {
         if(sub->SubscriptionID == subscriptionId)
@@ -135,6 +136,7 @@ UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscripti
         newMon->QueueSize = 1;
         newMon->DiscardOldest = UA_TRUE;
         newMon->handler = handlingFunction;
+        newMon->handlerContext = handlingContext;
         newMon->MonitoredItemId = response.results[0].monitoredItemId;
         LIST_INSERT_HEAD(&sub->MonitoredItems, newMon, listEntry);
         *newMonitoredItemId = newMon->MonitoredItemId;
@@ -233,7 +235,7 @@ UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response) {
                 // find this client handle
                 LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
                     if(mon->ClientHandle == mitemNot->clientHandle) {
-                        mon->handler(mitemNot->clientHandle, &mitemNot->value);
+                        mon->handler(mitemNot->clientHandle, &mitemNot->value, mon->handlerContext);
                         break;
                     }
                 }

+ 2 - 1
src/client/ua_client_internal.h

@@ -24,7 +24,8 @@ typedef struct UA_Client_MonitoredItem_s {
     UA_UInt32          SamplingInterval;
     UA_UInt32          QueueSize;
     UA_Boolean         DiscardOldest;
-    void               (*handler)(UA_UInt32 handle, UA_DataValue *value);
+    void               (*handler)(UA_UInt32 handle, UA_DataValue *value, void *context);
+    void               *handlerContext;
     LIST_ENTRY(UA_Client_MonitoredItem_s)  listEntry;
 } UA_Client_MonitoredItem;
 

+ 40 - 9
src/server/ua_server.c

@@ -1190,18 +1190,21 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 }
 
 UA_StatusCode
-__UA_Server_writeAttribute(UA_Server *server, const UA_NodeId nodeId,
-                             const UA_AttributeId attributeId, const UA_DataType *type,
-                             const void *value) {
+__UA_Server_write(UA_Server *server, const UA_NodeId *nodeId,
+                  const UA_AttributeId attributeId, const UA_DataType *type,
+                  const void *value) {
     UA_WriteValue wvalue;
     UA_WriteValue_init(&wvalue);
-    wvalue.nodeId = nodeId;
+    wvalue.nodeId = *nodeId;
     wvalue.attributeId = attributeId;
     if(attributeId != UA_ATTRIBUTEID_VALUE)
         /* hacked cast. the target WriteValue is used as const anyway */
         UA_Variant_setScalar(&wvalue.value.value, (void*)(uintptr_t)value, type);
-    else
+    else {
+        if(type != &UA_TYPES[UA_TYPES_VARIANT])
+            return UA_STATUSCODE_BADTYPEMISMATCH;
         wvalue.value.value = *(const UA_Variant*)value;
+    }
     wvalue.value.hasValue = UA_TRUE;
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
     return retval;
@@ -1258,11 +1261,11 @@ UA_Server_setObjectTypeNode_instanceLifecycleManagement(UA_Server *server, UA_No
 }
 
 UA_StatusCode
-__UA_Server_readAttribute(UA_Server *server, const UA_NodeId nodeId,
-                          const UA_AttributeId attributeId, void *v) {
+__UA_Server_read(UA_Server *server, const UA_NodeId *nodeId,
+                 const UA_AttributeId attributeId, void *v) {
     UA_ReadValueId item;
     UA_ReadValueId_init(&item);
-    item.nodeId = nodeId;
+    item.nodeId = *nodeId;
     item.attributeId = attributeId;
     UA_DataValue dv;
     UA_DataValue_init(&dv);
@@ -1277,7 +1280,8 @@ __UA_Server_readAttribute(UA_Server *server, const UA_NodeId nodeId,
         UA_DataValue_deleteMembers(&dv);
         return retval;
     }
-    if(attributeId == UA_ATTRIBUTEID_VALUE)
+    if(attributeId == UA_ATTRIBUTEID_VALUE ||
+       attributeId == UA_ATTRIBUTEID_ARRAYDIMENSIONS)
         memcpy(v, &dv.value, sizeof(UA_Variant));
     else {
         memcpy(v, dv.value.data, dv.value.type->memSize);
@@ -1287,3 +1291,30 @@ __UA_Server_readAttribute(UA_Server *server, const UA_NodeId nodeId,
     }
     return UA_STATUSCODE_GOOD;
 }
+
+UA_BrowseResult
+UA_Server_browse(UA_Server *server, UA_UInt32 maxrefs, const UA_BrowseDescription *descr) {
+    UA_BrowseResult result;
+    UA_BrowseResult_init(&result);
+    Service_Browse_single(server, &adminSession, NULL, descr, maxrefs, &result);
+    return result;
+}
+
+UA_BrowseResult
+UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
+                     const UA_ByteString *continuationPoint) {
+    UA_BrowseResult result;
+    UA_BrowseResult_init(&result);
+    UA_Server_browseNext_single(server, &adminSession, releaseContinuationPoint,
+                                continuationPoint, &result);
+    return result;
+}
+
+#ifdef ENABLE_METHODCALLS
+UA_CallMethodResult UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request) {
+    UA_CallMethodResult result;
+    UA_CallMethodResult_init(&result);
+    Service_Call_single(server, &adminSession, request, &result);
+    return result;
+}
+#endif

+ 12 - 4
src/server/ua_server_binary.c

@@ -142,7 +142,6 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
 
 static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r) {
     r->requestHandle = p->requestHandle;
-    r->stringTableSize = 0;
     r->timestamp = UA_DateTime_now();
 }
 
@@ -218,7 +217,6 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
         *responseType = &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE];
         break;
     case UA_NS0ID_PUBLISHREQUEST:
-        *service = (UA_Service)Service_Publish;
         *requestType = &UA_TYPES[UA_TYPES_PUBLISHREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_PUBLISHRESPONSE];
         break;
@@ -351,7 +349,7 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     const UA_DataType *requestType = NULL;
     const UA_DataType *responseType = NULL;
     getServicePointers(requestTypeId.identifier.numeric, &requestType, &responseType, &service);
-    if(!service) {
+    if(!requestType) {
         /* The service is not supported */
         if(requestTypeId.identifier.numeric==787)
             UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER,
@@ -408,8 +406,18 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     }
 #endif
 
-    /* Call the service */
     UA_Session_updateLifetime(session);
+
+#ifdef ENABLE_SUBSCRIPTIONS
+    /* The publish request is answered with a delay */
+    if(requestTypeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY == UA_NS0ID_PUBLISHREQUEST) {
+        Service_Publish(server, session, request, sequenceHeader.requestId);
+        UA_deleteMembers(request, requestType);
+        return;
+    }
+#endif
+        
+    /* Call the service */
     void *response = UA_alloca(responseType->memSize);
     UA_init(response, responseType);
     init_response_header(request, response);

+ 7 - 2
src/server/ua_services.h

@@ -173,6 +173,8 @@ void Service_Browse_single(UA_Server *server, UA_Session *session,
 void Service_BrowseNext(UA_Server *server, UA_Session *session,
                         const UA_BrowseNextRequest *request,
                         UA_BrowseNextResponse *response);
+void UA_Server_browseNext_single(UA_Server *server, UA_Session *session, UA_Boolean releaseContinuationPoint,
+                                 const UA_ByteString *continuationPoint, UA_BrowseResult *result);
 
 /** Used to translate textual node paths to their respective ids. */
 void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
@@ -267,6 +269,10 @@ void
 Service_Call(UA_Server *server, UA_Session *session,
              const UA_CallRequest *request,
              UA_CallResponse *response);
+void
+Service_Call_single(UA_Server *server, UA_Session *session,
+                    const UA_CallMethodRequest *request,
+                    UA_CallMethodResult *result);
 #endif
 /** @} */
 
@@ -327,8 +333,7 @@ Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
                                      
 void
 Service_Publish(UA_Server *server, UA_Session *session,
-                const UA_PublishRequest *request,
-                UA_PublishResponse *response);
+                const UA_PublishRequest *request, UA_UInt32 requestId);
 
 void
 Service_Republish(UA_Server *server, UA_Session *session,

+ 12 - 18
src/server/ua_services_attribute.c

@@ -561,11 +561,16 @@ CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) {
 }
 
 static UA_StatusCode
-CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_WriteValue *wvalue) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
+                      UA_Node *node, const UA_WriteValue *wvalue) {
+    if(!wvalue->value.hasValue)
+        return UA_STATUSCODE_BADNODATA;
+
     void *value = wvalue->value.value.data;
     void *target = NULL;
     const UA_DataType *type = NULL;
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
 	switch(wvalue->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
     case UA_ATTRIBUTEID_NODECLASS:
@@ -624,7 +629,10 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, con
 		break;
 	case UA_ATTRIBUTEID_VALUE:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = CopyValueIntoNode((UA_VariableNode*)node, wvalue);
+        if(((const UA_VariableNode*)node)->valueSource == UA_VALUESOURCE_VARIANT)
+            retval = CopyValueIntoNode((UA_VariableNode*)node, wvalue);
+        else
+            retval = Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)node, wvalue);
 		break;
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
@@ -668,21 +676,7 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, con
 }
 
 UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, const UA_WriteValue *wvalue) {
-    if(!wvalue->value.hasValue || !wvalue->value.value.data)
-        return UA_STATUSCODE_BADNODATA; // TODO: is this the right return code?
-    if(wvalue->attributeId == UA_ATTRIBUTEID_VALUE) {
-        const UA_Node *orig = UA_NodeStore_get(server->nodestore, &wvalue->nodeId);
-        if(!orig)
-            return UA_STATUSCODE_BADNODEIDUNKNOWN;
-        if(orig->nodeClass & (UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLE) &&
-           ((const UA_VariableNode*)orig)->valueSource == UA_VALUESOURCE_DATASOURCE) {
-            UA_StatusCode retval =
-                Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)orig, wvalue);
-            return retval;
-        }
-    }
-    return UA_Server_editNode(server, session, &wvalue->nodeId,
-                              (UA_EditNodeCallback)CopyAttributeIntoNode, wvalue);
+    return UA_Server_editNode(server, session, &wvalue->nodeId, (UA_EditNodeCallback)CopyAttributeIntoNode, wvalue);
 }
 
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,

+ 4 - 4
src/server/ua_services_call.c

@@ -105,9 +105,9 @@ argConformsToDefinition(const UA_VariableNode *argRequirements, size_t argsSize,
     return retval;
 }
 
-static void
-callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request,
-           UA_CallMethodResult *result) {
+void
+Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodRequest *request,
+                    UA_CallMethodResult *result) {
     const UA_MethodNode *methodCalled =
         (const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId);
     if(!methodCalled) {
@@ -206,5 +206,5 @@ void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *
     response->resultsSize = request->methodsToCallSize;
     
     for(size_t i = 0; i < request->methodsToCallSize;i++)
-        callMethod(server, session, &request->methodsToCall[i], &response->results[i]);
+        Service_Call_single(server, session, &request->methodsToCall[i], &response->results[i]);
 }

+ 41 - 28
src/server/ua_services_nodemanagement.c

@@ -695,36 +695,49 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     parent.nodeId = result.addedNodeId;
     
     /* create InputArguments */
-    UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
-    inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-    inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
-    inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-    inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-    inputArgumentsVariableNode->valueRank = 1;
-    UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
-                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-    UA_AddNodesResult inputAddRes;
+    /* FIXME:   The namespace compiler does currently not recognize the interdependancy between methods
+     *          and arguments - everything is treated as a standalone node.
+     *          In order to allow the compiler to create methods with arguments from an XML, this routine
+     *          must be coerced into *not* creating arguments, as these will be added by the compiler as
+     *          standalone nodes later. A semantic of inputArgumentsSize < 0 is used to signal this.
+     * 
+     *          This is not a production feature and should be fixed on the compiler side! (@ichrispa)
+     */
     const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
-    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
-                              &parent.nodeId, &hasproperty, &inputAddRes);
-    // todo: check if adding succeeded
-    UA_AddNodesResult_deleteMembers(&inputAddRes);
-
+    if (inputArgumentsSize >= 0) {
+      UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
+      inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+      inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
+      inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+      inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+      inputArgumentsVariableNode->valueRank = 1;
+      UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
+                              inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+      UA_AddNodesResult inputAddRes;
+      UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
+                                &parent.nodeId, &hasproperty, &inputAddRes);
+      // todo: check if adding succeeded
+      UA_AddNodesResult_deleteMembers(&inputAddRes);
+    }
+    
     /* create OutputArguments */
-    UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
-    outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-    outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
-    outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-    outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-    outputArgumentsVariableNode->valueRank = 1;
-    UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
-                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-    UA_AddNodesResult outputAddRes;
-    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
-                              &parent.nodeId, &hasproperty, &outputAddRes);
-    // todo: check if adding succeeded
-    UA_AddNodesResult_deleteMembers(&outputAddRes);
-
+    /* FIXME:   See comment in inputArguments */
+    if (outputArgumentsSize >= 0) {
+      UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
+      outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+      outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
+      outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+      outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+      outputArgumentsVariableNode->valueRank = 1;
+      UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
+                              outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+      UA_AddNodesResult outputAddRes;
+      UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
+                                &parent.nodeId, &hasproperty, &outputAddRes);
+      // todo: check if adding succeeded
+      UA_AddNodesResult_deleteMembers(&outputAddRes);
+    }
+    
     if(outNewNodeId)
         *outNewNodeId = result.addedNodeId;
     else

+ 44 - 32
src/server/ua_services_subscription.c

@@ -130,28 +130,36 @@ void Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
         createMonitoredItems(server, session, sub, &request->itemsToCreate[i], &response->results[i]);
 }
 
-void Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishRequest *request,
-                     UA_PublishResponse *response) {
+void
+Service_Publish(UA_Server *server, UA_Session *session,
+                const UA_PublishRequest *request, UA_UInt32 requestId) {
     UA_SubscriptionManager *manager= &session->subscriptionManager;
     if(!manager)
         return;
+
+    UA_PublishResponse response;
+    UA_PublishResponse_init(&response);
+    response.responseHeader.requestHandle = request->requestHeader.requestHandle;
+    response.responseHeader.timestamp = UA_DateTime_now();
     
     // Delete Acknowledged Subscription Messages
-    response->resultsSize = request->subscriptionAcknowledgementsSize;
-    response->results     = UA_malloc(sizeof(UA_StatusCode)*(response->resultsSize));
+    response.resultsSize = request->subscriptionAcknowledgementsSize;
+    response.results = UA_calloc(response.resultsSize, sizeof(UA_StatusCode));
     for(size_t i = 0; i < request->subscriptionAcknowledgementsSize; i++) {
-        response->results[i] = UA_STATUSCODE_GOOD;
-        UA_Subscription *sub =
-            SubscriptionManager_getSubscriptionByID(&session->subscriptionManager,
-                                                    request->subscriptionAcknowledgements[i].subscriptionId);
+        response.results[i] = UA_STATUSCODE_GOOD;
+        UA_UInt32 sid = request->subscriptionAcknowledgements[i].subscriptionId;
+        UA_Subscription *sub = SubscriptionManager_getSubscriptionByID(manager, sid);
         if(!sub) {
-            response->results[i] = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
+            response.results[i] = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
             continue;
         }
-        if(Subscription_deleteUnpublishedNotification(request->subscriptionAcknowledgements[i].sequenceNumber, false, sub) == 0)
-            response->results[i] = UA_STATUSCODE_BADSEQUENCENUMBERINVALID;
+        UA_UInt32 sn = request->subscriptionAcknowledgements[i].sequenceNumber;
+        if(Subscription_deleteUnpublishedNotification(sn, false, sub) == 0)
+            response.results[i] = UA_STATUSCODE_BADSEQUENCENUMBERINVALID;
     }
     
+    UA_Boolean have_response = UA_FALSE;
+
     // See if any new data is available
     UA_Subscription *sub;
     LIST_FOREACH(sub, &manager->serverSubscriptions, listEntry) {
@@ -181,39 +189,43 @@ void Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishReq
             continue;
     
         // We found an unpublished notification message in this subscription, which we will now publish.
-        response->subscriptionId = sub->subscriptionID;
-        Subscription_copyNotificationMessage(&response->notificationMessage, notification);
+        response.subscriptionId = sub->subscriptionID;
+        Subscription_copyNotificationMessage(&response.notificationMessage, notification);
         // Mark this notification as published
         notification->publishedOnce = UA_TRUE;
         if(notification->notification.sequenceNumber > sub->sequenceNumber) {
             // If this is a keepalive message, its seqNo is the next seqNo to be used for an actual msg.
-            response->availableSequenceNumbersSize = 0;
+            response.availableSequenceNumbersSize = 0;
             // .. and must be deleted
             Subscription_deleteUnpublishedNotification(sub->sequenceNumber + 1, false, sub);
         } else {
-            response->availableSequenceNumbersSize = sub->unpublishedNotificationsSize;
-            response->availableSequenceNumbers = Subscription_getAvailableSequenceNumbers(sub);
+            response.availableSequenceNumbersSize = sub->unpublishedNotificationsSize;
+            response.availableSequenceNumbers = Subscription_getAvailableSequenceNumbers(sub);
         }	  
-        // FIXME: This should be in processMSG();
-        session->validTill = UA_DateTime_now() + session->timeout * 10000;
-        return;
+        have_response = UA_TRUE;
     }
     
-    // FIXME: At this point, we would return nothing and "queue" the publish
-    // request, but currently we need to return something to the client. If no
-    // subscriptions have notifications, force one to generate a keepalive so we
-    // don't return an empty message
-    sub = LIST_FIRST(&manager->serverSubscriptions);
-    if(sub) {
-        response->subscriptionId = sub->subscriptionID;
-        sub->keepAliveCount.currentValue=sub->keepAliveCount.minValue;
-        Subscription_generateKeepAlive(sub);
-        Subscription_copyNotificationMessage(&response->notificationMessage, sub->unpublishedNotifications.lh_first);
-        Subscription_deleteUnpublishedNotification(sub->sequenceNumber + 1, false, sub);
+    if(!have_response) {
+        // FIXME: At this point, we would return nothing and "queue" the publish
+        // request, but currently we need to return something to the client. If no
+        // subscriptions have notifications, force one to generate a keepalive so we
+        // don't return an empty message
+        sub = LIST_FIRST(&manager->serverSubscriptions);
+        if(sub) {
+            response.subscriptionId = sub->subscriptionID;
+            sub->keepAliveCount.currentValue=sub->keepAliveCount.minValue;
+            Subscription_generateKeepAlive(sub);
+            Subscription_copyNotificationMessage(&response.notificationMessage,
+                                                 LIST_FIRST(&sub->unpublishedNotifications));
+            Subscription_deleteUnpublishedNotification(sub->sequenceNumber + 1, false, sub);
+        }
     }
     
-    // FIXME: This should be in processMSG();
-    session->validTill = UA_DateTime_now() + session->timeout * 10000;
+    UA_SecureChannel *channel = session->channel;
+    if(channel)
+        UA_SecureChannel_sendBinaryMessage(channel, requestId, &response,
+                                           &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
+    UA_PublishResponse_deleteMembers(&response);
 }
 
 void Service_ModifySubscription(UA_Server *server, UA_Session *session,

+ 20 - 14
src/server/ua_services_view.c

@@ -419,6 +419,23 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
     }
 }
 
+void
+UA_Server_browseNext_single(UA_Server *server, UA_Session *session, UA_Boolean releaseContinuationPoint,
+                            const UA_ByteString *continuationPoint, UA_BrowseResult *result) {
+    result->statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
+    struct ContinuationPointEntry *cp, *temp;
+    LIST_FOREACH_SAFE(cp, &session->continuationPoints, pointers, temp) {
+        if(UA_ByteString_equal(&cp->identifier, continuationPoint)) {
+            result->statusCode = UA_STATUSCODE_GOOD;
+            if(!releaseContinuationPoint)
+                Service_Browse_single(server, session, cp, NULL, 0, result);
+            else
+                removeCp(cp, session);
+            break;
+        }
+    }
+}
+
 void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseNextRequest *request,
                         UA_BrowseNextResponse *response) {
     UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
@@ -436,20 +453,9 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
    }
 
    response->resultsSize = size;
-   for(size_t i = 0; i < size; i++) {
-       response->results[i].statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
-       struct ContinuationPointEntry *cp, *temp;
-       LIST_FOREACH_SAFE(cp, &session->continuationPoints, pointers, temp) {
-           if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
-               response->results[i].statusCode = UA_STATUSCODE_GOOD;
-               if(!request->releaseContinuationPoints)
-                   Service_Browse_single(server, session, cp, NULL, 0, &response->results[i]);
-               else
-                   removeCp(cp, session);
-               break;
-           }
-       }
-   }
+   for(size_t i = 0; i < size; i++)
+       UA_Server_browseNext_single(server, session, request->releaseContinuationPoints,
+                                   &request->continuationPoints[i], &response->results[i]);
 }
 
 /***********************/

+ 15 - 2
src/ua_types.c

@@ -537,6 +537,19 @@ UA_Variant_setArrayCopy(UA_Variant *v, const void *array,
     return UA_STATUSCODE_GOOD;
 }
 
+/* LocalizedText */
+static void LocalizedText_deleteMembers(UA_LocalizedText *p, const UA_DataType *_) {
+    UA_String_deleteMembers(&p->locale);
+    UA_String_deleteMembers(&p->text);
+}
+
+static UA_StatusCode
+LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedText *dst, const UA_DataType *_) {
+    UA_StatusCode retval = UA_String_copy(&src->locale, &dst->locale);
+    retval |= UA_String_copy(&src->text, &dst->text);
+    return retval;
+}
+
 /* DataValue */
 static void DataValue_deleteMembers(UA_DataValue *p, const UA_DataType *_) {
     Variant_deletemembers(&p->value, NULL);
@@ -623,7 +636,7 @@ static const UA_copySignature copyJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = {
     (UA_copySignature)UA_copyNoInit, // ExpandedNodeId
     (UA_copySignature)UA_copyFixedSize, // StatusCode
     (UA_copySignature)UA_copyNoInit, // QualifiedName
-    (UA_copySignature)UA_copyNoInit, // LocalizedText
+    (UA_copySignature)LocalizedText_copy, // LocalizedText
     (UA_copySignature)ExtensionObject_copy,
     (UA_copySignature)DataValue_copy,
     (UA_copySignature)Variant_copy,
@@ -696,7 +709,7 @@ static const UA_deleteMembersSignature deleteMembersJumpTable[UA_BUILTIN_TYPES_C
     (UA_deleteMembersSignature)UA_deleteMembers, // ExpandedNodeId
     (UA_deleteMembersSignature)nopDeleteMembers, // StatusCode
     (UA_deleteMembersSignature)UA_deleteMembers, // QualifiedName
-    (UA_deleteMembersSignature)UA_deleteMembers, // LocalizedText
+    (UA_deleteMembersSignature)LocalizedText_deleteMembers, // LocalizedText
     (UA_deleteMembersSignature)ExtensionObject_deleteMembers,
     (UA_deleteMembersSignature)DataValue_deleteMembers,
     (UA_deleteMembersSignature)Variant_deletemembers,

+ 0 - 20
tools/.checkPorts.sh

@@ -1,20 +0,0 @@
-#!/bin/bash
-
-#
-# This script checks whether all patches from /ports dir are applicable
-#
-
-PATCHES=ports/*
-
-for p in $PATCHES
-do
-	git apply --check $p
-	if [[ "$?" == 0 ]] 
-	then
-		echo $p is applicable
-	else
-		echo failed to apply $p
-		exit 1
-	fi
-	
-done

+ 0 - 20
tools/.deployGH_doc.sh

@@ -1,20 +0,0 @@
-#!/bin/bash
-
-#
-# This script is run by travis-ci and pushes generated
-# Doxygen docs and single-source distributions to open62541-www
-#
-
-git clone --depth=5 -b gh-pages https://$GITAUTH@github.com/acplt/open62541-www
-cd open62541-www
-#handle doc
-git rm -r -f doc
-cp -r ../doc ./
-git add -A doc/*
-git config --global user.email "open62541-travis-ci@users.noreply.github.com"
-git config --global user.name "Open62541 travis-ci"
-git config --global push.default simple
-git commit -am "updated generated documentation on webpage by travis-ci [ci skip]"
-git push https://$GITAUTH@github.com/acplt/open62541-www
-cd ..
-rm -rf open62541-www

+ 0 - 54
tools/.deployGH_release.sh

@@ -1,54 +0,0 @@
-#!/bin/bash
-
-#
-# This script is run by travis-ci and pushes generated
-# Doxygen docs and single-source distributions to open62541-www
-#
-TAGSTOSAVE=50
-
-#current tag info
-TAG="$(git rev-parse --short=10 HEAD)"
-BRANCH="$(git log --pretty=format:"%d" --date=iso --abbrev=10 --all -1)"
-DATE="$(git log --pretty=format:"%ad" --date=iso --abbrev=10 --all -1)"
-COMMENT="$(git log --pretty=format:"%s" --date=iso --abbrev=10 --all -1)"
-
-git clone --depth=5 -b gh-pages https://$GITAUTH@github.com/acplt/open62541-www
-cd open62541-www
-#hanndle releases
-cd releases
-if [ ! -e "$TAG.zip" ]; then
-#add the first line
-echo "<tr><td><a href='./$TAG.zip'>$TAG</a></td><td>$BRANCH</td><td>$DATE</td><td>$COMMENT</td></tr>" | cat - rawtable.txt > temp && mv temp rawtable.txt
-
-#keep top lines only
-head "-$TAGSTOSAVE" rawtable.txt > temp && mv temp rawtable.txt
-
-#compose the index file
-cat head.txt rawtable.txt foot.txt > index.html
-
-#create a zip for single-file release and copy the files
-cp ../../open62541.c .
-cp ../../open62541.h .
-zip -r "$TAG.zip" open62541.c open62541.h
-rm open62541.c
-rm open62541.h
-git add "$TAG.zip"
-
-echo "$TAG.zip" | cat - raw.txt > temp && mv temp raw.txt
-
-LINETOSTART=$((TAGSTOSAVE+1))
-#remove obsolete zips
-tail -n +"$LINETOSTART" raw.txt | xargs git rm
-
-#remove obsolete zips from list
-head "-$TAGSTOSAVE" raw.txt > temp && mv temp raw.txt
-fi
-cd ..
-
-git config --global user.email "open62541-travis-ci@users.noreply.github.com"
-git config --global user.name "Open62541 travis-ci"
-git config --global push.default simple
-git commit -am "added release files and updated releases webpage by travis-ci [ci skip]"
-git push https://$GITAUTH@github.com/acplt/open62541-www
-cd ..
-rm -rf open62541-www

+ 0 - 13
tools/generate_datatypes.py

@@ -178,19 +178,6 @@ class BuiltinType(Type):
                 ".padding = offsetof(UA_QualifiedName, name)-sizeof(UA_UInt16), .isArray = UA_FALSE }},\n" + \
                 ".typeIndex = UA_TYPES_QUALIFIEDNAME }"
 
-        if self.name == "UA_LocalizedText":
-            return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-                ".memSize = sizeof(UA_LocalizedText), " + \
-                ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
-                ".membersSize = 2, .members = {" + \
-                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
-                (".memberName = \"locale\", " if typeintrospection else "") + \
-                ".padding = 0, .isArray = UA_FALSE }," + \
-                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
-                (".memberName = \"text\", " if typeintrospection else "") + \
-                ".padding = offsetof(UA_LocalizedText, text)-sizeof(UA_String), .isArray = UA_FALSE }},\n" + \
-                ".typeIndex = UA_TYPES_LOCALIZEDTEXT }"
-
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             ".memSize = sizeof(" + self.name + "), " + \
             ".builtin = UA_TRUE, .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \

+ 9 - 2
tools/pyUANamespace/open62541_MacroHelper.py

@@ -115,6 +115,9 @@ class open62541_MacroHelper():
     code.append("attr.displayName = UA_LOCALIZEDTEXT(\"\", \"" + str(node.displayName()) + "\");")
     code.append("attr.description = UA_LOCALIZEDTEXT(\"\", \"" + str(node.description()) + "\");")
     
+    if nodetype in ["Variable", "VariableType"]:
+      code = code + node.printOpen62541CCode_SubtypeEarly(bootstrapping = False)
+    
     code.append("UA_NodeId nodeId = " + str(self.getCreateNodeIDMacro(node)) + ";")
     if nodetype in ["Object", "Variable"]:
       code.append("UA_NodeId typeDefinition = UA_NODEID_NULL;") # todo instantiation of object and variable types
@@ -125,7 +128,9 @@ class open62541_MacroHelper():
       code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(" +  str(extrNs[0]) + ", \"" + extrNs[1] + "\");")
     else:
       code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"" + str(node.browseName()) + "\");")
-
+    
+    # In case of a MethodNode: Add in|outArg struct generation here. Mandates that namespace reordering was done using 
+    # Djikstra (check that arguments have not been printed). (@ichrispa)
     code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
       
     if nodetype in ["Object", "Variable"]:
@@ -134,7 +139,9 @@ class open62541_MacroHelper():
     if nodetype != "Method":
       code.append("       , attr, NULL);")
     else:
-      code.append("       , attr, (UA_MethodCallback) NULL, NULL, 0, NULL, 0, NULL, NULL);")
+      # FIXME:  Semantic of inputArgumentSize = -1 is used to signal the suppression of argument creation.
+      #         This should be replaced with a properly generated struct for the arguments.
+      code.append("       , attr, (UA_MethodCallback) NULL, NULL, -1, NULL, -1, NULL, NULL);")
     return code
     
   def getCreateNodeBootstrap(self, node):

+ 15 - 17
tools/pyUANamespace/ua_builtin_types.py

@@ -353,8 +353,7 @@ class opcua_value_t():
           for v in self.value:
             log(self, "Building extObj array index " + str(self.value.index(v)))
             code = code + v.printOpen62541CCode_SubType_build(arrayIndex=self.value.index(v))
-        code.append("UA_Variant *" + self.parent.getCodePrintableID() + "_variant = UA_Variant_new();")
-        code.append(self.parent.getCodePrintableID() + "_variant->type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
+        #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
         code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + "[" + str(len(self.value)) + "];")
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           for v in self.value:
@@ -364,7 +363,7 @@ class opcua_value_t():
         else:
           for v in self.value:
             code.append(valueName + "[" + str(self.value.index(v)) + "] = " + v.printOpen62541CCode_SubType() + ";")
-        code.append("UA_Variant_setArrayCopy(" + self.parent.getCodePrintableID() + "_variant, &" + valueName +
+        code.append("UA_Variant_setArrayCopy( &attr.value, &" + valueName +
                     ", (UA_Int32) " + str(len(self.value)) + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
     else:
       # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
@@ -380,16 +379,15 @@ class opcua_value_t():
         # The following strategy applies to all other types, in particular strings and numerics.
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           code = code + self.value[0].printOpen62541CCode_SubType_build()
-        code.append("UA_Variant *" + self.parent.getCodePrintableID() + "_variant = UA_Variant_new();")
-        code.append(self.parent.getCodePrintableID() + "_variant->type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
+        #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           code.append("UA_" + self.value[0].stringRepresentation + " *" + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          code.append("UA_Variant_setScalarCopy(" + self.parent.getCodePrintableID() + "_variant, " + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
+          code.append("UA_Variant_setScalarCopy( &attr.value, " + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
           #FIXME: There is no membership definition for extensionObjects generated in this function.
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
         else:
           code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          code.append("UA_Variant_setScalarCopy(" + self.parent.getCodePrintableID() + "_variant, &" + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
+          code.append("UA_Variant_setScalarCopy( &attr.value, &" + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(&" + valueName + ");")
     return code
 
@@ -477,9 +475,9 @@ class opcua_BuiltinType_extensionObject_t(opcua_value_t):
 
     # Allocate some memory
     code.append("UA_ExtensionObject *" + self.getCodeInstanceName() + " =  UA_ExtensionObject_new();")
-    code.append(self.getCodeInstanceName() + "->encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;")
-    code.append(self.getCodeInstanceName() + "->typeId = UA_NODEID_NUMERIC(" + str(self.parent.dataType().target().id().ns) + ", " + str(self.parent.dataType().target().id().i) + "+ UA_ENCODINGOFFSET_BINARY);")
-    code.append("UA_ByteString_newMembers(&" + self.getCodeInstanceName() + "->body, 65000);" )
+    code.append(self.getCodeInstanceName() + "->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;")
+    code.append(self.getCodeInstanceName() + "->content.encoded.typeId = UA_NODEID_NUMERIC(" + str(self.parent.dataType().target().id().ns) + ", " + str(self.parent.dataType().target().id().i) + "+ UA_ENCODINGOFFSET_BINARY);")
+    code.append("if(UA_ByteString_allocBuffer(&" + self.getCodeInstanceName() + "->content.encoded.body, 65000) != UA_STATUSCODE_GOOD) {}" )
 
     # Encode each value as a bytestring seperately.
     code.append("size_t " + self.getCodeInstanceName() + "_encOffset = 0;" )
@@ -488,20 +486,20 @@ class opcua_BuiltinType_extensionObject_t(opcua_value_t):
       encField = self.getEncodingRule()[encFieldIdx]
       encFieldIdx = encFieldIdx + 1;
       if encField[2] == 0:
-        code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + ", &" + self.getCodeInstanceName() + "->body, &" + self.getCodeInstanceName() + "_encOffset);" )
+        code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + ", &" + self.getCodeInstanceName() + "->content.encoded.body, &" + self.getCodeInstanceName() + "_encOffset);" )
       else:
         if isinstance(subv, list):
           for subvidx in range(0,len(subv)):
-            code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[" + str(subvidx) + "], &" + self.getCodeInstanceName() + "->body, &" + self.getCodeInstanceName() + "_encOffset);" )
+            code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[" + str(subvidx) + "], &" + self.getCodeInstanceName() + "->content.encoded.body, &" + self.getCodeInstanceName() + "_encOffset);" )
         else:
-          code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[0], &" + self.getCodeInstanceName() + "->body, &" + self.getCodeInstanceName() + "_encOffset);" )
+          code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[0], &" + self.getCodeInstanceName() + "->content.encoded.body, &" + self.getCodeInstanceName() + "_encOffset);" )
 
     # Reallocate the memory by swapping the 65k Bytestring for a new one
-    code.append(self.getCodeInstanceName() + "->body.length = " + self.getCodeInstanceName() + "_encOffset;");
+    code.append(self.getCodeInstanceName() + "->content.encoded.body.length = " + self.getCodeInstanceName() + "_encOffset;");
     code.append("UA_Byte *" + self.getCodeInstanceName() + "_newBody = (UA_Byte *) UA_malloc(" + self.getCodeInstanceName() + "_encOffset );" )
-    code.append("memcpy(" + self.getCodeInstanceName() + "_newBody, " + self.getCodeInstanceName() + "->body.data, " + self.getCodeInstanceName() + "_encOffset);" )
-    code.append("UA_Byte *" + self.getCodeInstanceName() + "_oldBody = " + self.getCodeInstanceName() + "->body.data;");
-    code.append(self.getCodeInstanceName() + "->body.data = " +self.getCodeInstanceName() + "_newBody;")
+    code.append("memcpy(" + self.getCodeInstanceName() + "_newBody, " + self.getCodeInstanceName() + "->content.encoded.body.data, " + self.getCodeInstanceName() + "_encOffset);" )
+    code.append("UA_Byte *" + self.getCodeInstanceName() + "_oldBody = " + self.getCodeInstanceName() + "->content.encoded.body.data;");
+    code.append(self.getCodeInstanceName() + "->content.encoded.body.data = " +self.getCodeInstanceName() + "_newBody;")
     code.append("UA_free(" + self.getCodeInstanceName() + "_oldBody);")
     code.append("")
     return code

+ 3 - 0
tools/pyUANamespace/ua_namespace.py

@@ -640,6 +640,9 @@ class opcua_namespace():
     header.append('#include "server/ua_nodes.h"')
     header.append('#include "ua_util.h"')
     header.append('#include "ua_types.h"')
+    header.append('#include "ua_types_encoding_binary.h"')
+    header.append('#include "ua_types_generated_encoding_binary.h"')
+    header.append('#include "ua_transport_generated_encoding_binary.h"')
     header.append('#else')
     header.append('#include "open62541.h"')
     header.append('#define NULL ((void *)0)')

+ 4 - 2
tools/pyUANamespace/ua_node_types.py

@@ -1069,7 +1069,8 @@ class opcua_node_variable_t(opcua_node_t):
         if self.value() != None:
           code = code + self.value().printOpen62541CCode(bootstrapping)
           return code
-    code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
+    if(bootstrapping):
+      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
     return code
   
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
@@ -1323,7 +1324,8 @@ class opcua_node_variableType_t(opcua_node_t):
         if self.value() != None:
           code = code + self.value().printOpen62541CCode(bootstrapping)
           return code
-    code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
+    if(bootstrapping):
+      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
     return code
   
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):

+ 1 - 2
tools/travis_linux_before_install.sh

@@ -4,7 +4,7 @@ sudo apt-get update
 sudo apt-get install binutils-mingw-w64-i686 gcc-mingw-w64-i686 mingw-w64
 sudo add-apt-repository ppa:kalakris/cmake -y
 sudo apt-get update -qq
-sudo apt-get install -qq --no-install-recommends build-essential cmake python-lxml gcc-multilib graphviz doxygen wget zip
+sudo apt-get install -qq --no-install-recommends build-essential cmake python-lxml gcc-multilib wget zip
 sudo apt-get install libsubunit-dev #for check_0.10.0
 wget http://ftp.de.debian.org/debian/pool/main/c/check/check_0.10.0-3_amd64.deb
 sudo dpkg -i check_0.10.0-3_amd64.deb
@@ -14,5 +14,4 @@ sudo dpkg -i liburcu2_0.8.5-1ubuntu1_amd64.deb
 sudo dpkg -i liburcu-dev_0.8.5-1ubuntu1_amd64.deb
 sudo pip install cpp-coveralls
 sudo pip install sphinx
-sudo pip install breathe
 sudo pip install sphinx_rtd_theme

+ 28 - 31
tools/travis_linux_script.sh

@@ -7,49 +7,43 @@ cd build
 cmake -DCMAKE_BUILD_TYPE=Release -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON -DUA_BUILD_EXAMPLES=ON -DUA_BUILD_DOCUMENTATION=ON -DUA_BUILD_SELFSIGNED_CERTIFICATE=ON ..
 make doc
 make selfsigned
-cp -r doc ..
-cp server_cert.der ..
+cp -r doc ../../
+cp server_cert.der ../../
+cd .. && rm build -rf 
 
-echo "Testing builds"
-cd .. && rm build -rf && mkdir -p build && cd build
 echo "Cross compile release build for MinGW 32 bit"
+mkdir -p build && cd build
 cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw32.cmake -DUA_ENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON -DUA_BUILD_EXAMPLES=ON ..
 make
-cp ../README.md .
-cp ../LICENSE .
-cp ../AUTHORS .
-cp -r ../doc .
-cp ../server_cert.der .
-zip -r open62541-win32.zip doc server_cert.der LICENSE AUTHORS README.md server_static.exe server.exe client.exe client_static.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
+zip -r open62541-win32.zip ../../doc ../../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static.exe server.exe client.exe client_static.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
 cp open62541-win32.zip ..
-cd .. && rm build -rf && mkdir -p build && cd build
+cd .. && rm build -rf 
 
 echo "Cross compile release build for MinGW 64 bit"
+mkdir -p build && cd build
 cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw64.cmake -DUA_ENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON -DUA_BUILD_EXAMPLES=ON ..
 make
-cp ../README.md .
-cp ../LICENSE .
-cp ../AUTHORS .
-cp -r ../doc .
-cp ../server_cert.der .
-zip -r open62541-win64.zip doc server_cert.der LICENSE AUTHORS README.md server_static.exe server.exe client.exe client_static.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
+zip -r open62541-win64.zip ../../doc ../../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static.exe server.exe client.exe client_static.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
 cp open62541-win64.zip ..
-cd .. && rm build -rf && mkdir -p build && cd build
+cd .. && rm build -rf 
 
 echo "Cross compile release build for 32-bit linux"
+mkdir -p build && cd build
 cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-gcc-m32.cmake -DUA_ENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON ..
 make
-tar -pczf open62541-linux32.tar.gz ../doc ../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static server client_static client libopen62541.so open62541.h open62541.c
+tar -pczf open62541-linux32.tar.gz ../../doc ../../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static server client_static client libopen62541.so open62541.h open62541.c
 cp open62541-linux32.tar.gz ..
-cd .. && rm build -rf && mkdir -p build && cd build
+cd .. && rm build -rf 
 
 echo "Compile release build for 64-bit linux"
+mkdir -p build && cd build
 cmake -DCMAKE_BUILD_TYPE=Release -DUA_ENABLE_AMALGAMATION=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON ..
 make
-tar -pczf open62541-linux64.tar.gz ../doc ../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static server client_static client libopen62541.so open62541.h open62541.c
+tar -pczf open62541-linux64.tar.gz ../../doc ../../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static server client_static client libopen62541.so open62541.h open62541.c
 cp open62541-linux64.tar.gz ..
-cp open62541.h .. #copy single file-release
-cp open62541.c .. #copy single file-release
+cp open62541.h ../../ #copy single file-release
+cp open62541.c ../../ #copy single file-release
+cd .. && rm build -rf 
 
 echo "Upgrade to gcc 4.8"
 sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
@@ -59,21 +53,24 @@ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20
 sudo update-alternatives --config gcc
 
 echo "Building the C++ example"
+mkdir -p build && cd build
+cp ../../open62541.* .
 gcc -std=c99 -c open62541.c
 g++-4.8 ../examples/server.cpp -I./ open62541.o -o cpp-server
-cd .. && rm build -rf && mkdir -p build && cd build
+cd .. && rm build -rf 
 
 echo "Compile multithreaded version"
+mkdir -p build && cd build
 cmake -DUA_ENABLE_MULTITHREADING=ON -DUA_BUILD_EXAMPLESERVER=ON ..
 make
-cd .. && rm build -rf && mkdir -p build && cd build
+cd .. && rm build -rf 
 
+#this run inclides full examples and methodcalls
 echo "Debug build and unit tests (64 bit)"
-cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_UNIT_TESTS=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_ENABLE_COVERAGE=ON ..
+mkdir -p build && cd build
+cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_METHODCALLS=ON -DUA_BUILD_DEMO_NODESET=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_ENABLE_COVERAGE=ON ..
 make && make test ARGS="-V"
 echo "Run valgrind to see if the server leaks memory (just starting up and closing..)"
-if [[ ! ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "clang") ]]; then
-  (valgrind --error-exitcode=3 ./server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);
-  (coveralls --gcov /usr/bin/gcov-4.8 -E '.*\.h' -E '.*CMakeCXXCompilerId\.cpp' -E '.*CMakeCCompilerId\.c' -r ../ ; exit 0);
-fi
-cd ..
+(valgrind --error-exitcode=3 ./server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);
+coveralls --gcov /usr/bin/gcov-4.8 -E '.*\.h' -E '.*CMakeCXXCompilerId\.cpp' -E '.*CMakeCCompilerId\.c' -r ../
+cd .. && rm build -rf

+ 1 - 3
tools/travis_osx_before_install.sh

@@ -4,11 +4,9 @@ brew install cmake
 brew install check
 brew install libxml2
 brew install userspace-rcu
-brew install graphviz
-brew install doxygen
-brew install swig
 brew install --HEAD valgrind
 
 sudo pip install lxml
 sudo pip install sphinx
 sudo pip install breathe
+sudo pip install sphinx_rtd_theme

+ 12 - 16
tools/travis_osx_script.sh

@@ -1,30 +1,26 @@
 #!/bin/bash
 set -ev
-echo "Documentation and certificate build"
-mkdir -p build
-cd build
-cmake -DCMAKE_BUILD_TYPE=Release -DUA_BUILD_DOCUMENTATION=ON -DUA_BUILD_SELFSIGNED_CERTIFICATE=ON ..
-make doc
-make selfsigned
-cp -r doc ..
-cp server_cert.der ..
-echo "Testing builds"
-cd .. && rm -rf build && mkdir -p build && cd build
+
 echo "Compile release build for OS X"
-cmake -DCMAKE_BUILD_TYPE=Release -DUA_ENABLE_AMALGAMATION=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON ..
+mkdir -p build && cd build
+cmake -DCMAKE_BUILD_TYPE=Release -DUA_ENABLE_AMALGAMATION=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON -DUA_BUILD_DOCUMENTATION=ON -DUA_GENERATE_SELFSIGNED=ON ..
 make
 tar -pczf open62541-osx.tar.gz ../doc ../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static server client_static client libopen62541.dylib open62541.h open62541.c
 cp open62541-osx.tar.gz ..
 cp open62541.h .. #copy single file-release
 cp open62541.c .. #copy single file-release
-cd .. && rm -rf build && mkdir -p build && cd build
+cd .. && rm -rf build
+
 echo "Compile multithreaded version"
-cmake -DENABLE_MULTITHREADING=ON -DBUILD_EXAMPLESERVER=ON ..
+mkdir -p build && cd build
+cmake -DUA_ENABLE_MULTITHREADING=ON -DUA_BUILD_EXAMPLESERVER=ON ..
 make
-cd .. && rm -rf build && mkdir -p build && cd build
+cd .. && rm -rf build
+
 echo "Debug build and unit tests (64 bit)"
-cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_UNIT_TESTS=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_ENABLE_COVERAGE=ON ..
+mkdir -p build && cd build
+cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_DEMO_NODESET=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_ENABLE_COVERAGE=ON ..
 make && make test
 echo "Run valgrind to see if the server leaks memory (just starting up and closing..)"
 (valgrind --error-exitcode=3 ./server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);
-cd ..
+cd .. && rm -rf build

+ 0 - 0
tools/.coverity.sh


+ 14 - 0
tools/travis_push_doc.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+git clone --depth=5 -b gh-pages https://$GITAUTH@github.com/open62541/open62541-www
+cd open62541-www
+
+git rm -r -f ./doc/current/*
+cp -r ../../doc/* ./doc/current/
+git add -A ./doc/current
+git config --global user.email "open62541-travis-ci@users.noreply.github.com"
+git config --global user.name "Open62541 travis-ci"
+git config --global push.default simple
+git commit -am "updated generated documentation on webpage by travis-ci [ci skip]"
+git push https://$GITAUTH@github.com/open62541/open62541-www
+cd .. && rm -rf open62541-www

+ 49 - 0
tools/travis_push_release.sh

@@ -0,0 +1,49 @@
+#!/bin/bash
+
+TAGSTOSAVE=50
+TAG="$(git rev-parse --short=10 HEAD)"
+BRANCH="$(git log --pretty=format:"%d" --date=iso --abbrev=10 --all -1)"
+DATE="$(git log --pretty=format:"%ad" --date=iso --abbrev=10 --all -1)"
+COMMENT="$(git log --pretty=format:"%s" --date=iso --abbrev=10 --all -1)"
+
+git clone --depth=5 -b gh-pages https://$GITAUTH@github.com/open62541/open62541-www
+cd open62541-www
+
+#hanndle releases
+cd releases
+if [ ! -e "$TAG.zip" ]; then
+    #add the first line
+    echo "<tr><td><a href='./$TAG.zip'>$TAG</a></td><td>$BRANCH</td><td>$DATE</td><td>$COMMENT</td></tr>" | cat - rawtable.txt > temp && mv temp rawtable.txt
+
+    #keep top lines only
+    head "-$TAGSTOSAVE" rawtable.txt > temp && mv temp rawtable.txt
+
+    #compose the index file
+    cat head.txt rawtable.txt foot.txt > index.html
+
+    #create a zip for single-file release and copy the files
+    cp ../../../open62541.c .
+    cp ../../../open62541.h .
+    zip -r "$TAG.zip" open62541.c open62541.h
+    rm open62541.c
+    rm open62541.h
+    git add "$TAG.zip"
+
+    echo "$TAG.zip" | cat - raw.txt > temp && mv temp raw.txt
+
+    LINETOSTART=$((TAGSTOSAVE+1))
+    #remove obsolete zips
+    tail -n +"$LINETOSTART" raw.txt | xargs git rm
+
+    #remove obsolete zips from list
+    head "-$TAGSTOSAVE" raw.txt > temp && mv temp raw.txt
+fi
+cd ..
+
+git config --global user.email "open62541-travis-ci@users.noreply.github.com"
+git config --global user.name "Open62541 travis-ci"
+git config --global push.default simple
+git commit -am "added release files and updated releases webpage by travis-ci [ci skip]"
+git push https://$GITAUTH@github.com/open62541/open62541-www
+cd ..
+rm -rf open62541-www