Browse Source

Merge branch 'master' into api_hl_abstractions

Conflicts:
	examples/server.c
	examples/server_method.c
	examples/server_variable.c
	src/server/ua_server_addressspace.c
ichrispa 9 years ago
parent
commit
7737b4ffbf

+ 2 - 2
CMakeLists.txt

@@ -118,7 +118,7 @@ file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src_generated")
 
 option(ENABLE_SUBSCRIPTIONS "Enable compilation of subscription and monitoring support." OFF)
 if(ENABLE_SUBSCRIPTIONS)
-  add_definitions(-DENABLE_SUBSCRIPTIONS)
+  set(ENABLE_SUBSCRIPTIONS ON) #to propagate it to the config file
   list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_services_subscription.c
                           ${PROJECT_SOURCE_DIR}/src/server/ua_subscription.c
                           ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_manager.c)
@@ -185,7 +185,7 @@ set(UA_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported")
 # Enable Methodcall service
 option(ENABLE_METHODCALLS "Enable CallMethod/MethodCall service set" OFF)
 if(ENABLE_METHODCALLS)
-    add_definitions(-DENABLE_METHODCALLS)
+    set(ENABLE_METHODCALLS ON) #to propagate it to the config file
     list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_services_call.c)
 endif()
 

+ 1 - 1
examples/client.c

@@ -34,11 +34,11 @@ int main(int argc, char *argv[]) {
     UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
     UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
                                              "opc.tcp://localhost:16664");
+
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         return retval;
     }
-
     // Browse some objects
     printf("Browsing nodes in objects folder:\n");
 

+ 28 - 12
examples/networklayer_tcp.c

@@ -23,6 +23,9 @@
 # include <netdb.h> //gethostbyname for the client
 # include <unistd.h> // read, write, close
 # include <arpa/inet.h>
+#ifdef __QNX__
+#include <sys/socket.h>
+#endif
 # define CLOSESOCKET(S) close(S)
 #endif
 
@@ -34,6 +37,12 @@
 /* Generic Socket Functions */
 /****************************/
 
+static void socket_close(UA_Connection *connection) {
+    connection->state = UA_CONNECTION_CLOSED;
+    shutdown(connection->sockfd,2);
+    CLOSESOCKET(connection->sockfd);
+}
+
 static UA_StatusCode socket_write(UA_Connection *connection, UA_ByteString *buf, size_t buflen) {
     size_t nWritten = 0;
     while (nWritten < buflen) {
@@ -41,12 +50,17 @@ static UA_StatusCode socket_write(UA_Connection *connection, UA_ByteString *buf,
         do {
 #ifdef _WIN32
             n = send((SOCKET)connection->sockfd, (const char*)buf->data, buflen, 0);
-            if(n < 0 && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
+            if(n < 0 && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK){
+                connection->close(connection);
+                socket_close(connection);
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
+            }
 #else
             n = send(connection->sockfd, (const char*)buf->data, buflen, MSG_NOSIGNAL);
-            if(n == -1L && errno != EINTR && errno != EAGAIN)
+            if(n == -1L && errno != EINTR && errno != EAGAIN){
+                socket_close(connection);
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
+            }
 #endif
         } while (n == -1L);
         nWritten += n;
@@ -57,12 +71,6 @@ static UA_StatusCode socket_write(UA_Connection *connection, UA_ByteString *buf,
     return UA_STATUSCODE_GOOD;
 }
 
-static void socket_close(UA_Connection *connection) {
-    connection->state = UA_CONNECTION_CLOSED;
-    shutdown(connection->sockfd,2);
-    CLOSESOCKET(connection->sockfd);
-}
-
 static UA_StatusCode socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout) {
     response->data = malloc(connection->localConf.recvBufferSize);
     if(!response->data) {
@@ -354,6 +362,12 @@ static UA_Int32 ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job
         j++;
     }
 
+    if (j == 0)
+    {
+    	free(js);
+    	js = NULL;
+    }
+
     *jobs = js;
     return j;
 }
@@ -444,13 +458,14 @@ static void ClientNetworkLayerReleaseBuffer(UA_Connection *connection, UA_ByteSt
 }
 
 static void ClientNetworkLayerClose(UA_Connection *connection) {
+#ifndef UA_MULTITHREADING
+    UA_ByteString_delete(connection->handle);
+    connection->handle = NULL;
+#endif
     if(connection->state == UA_CONNECTION_CLOSED)
         return;
     connection->state = UA_CONNECTION_CLOSED;
     socket_close(connection);
-#ifndef UA_MULTITHREADING
-    UA_ByteString_delete(connection->handle);
-#endif
 }
 
 /* we have no networklayer. instead, attach the reusable buffer to the handle */
@@ -514,11 +529,12 @@ UA_Connection ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, char
     memcpy((char *)&server_addr.sin_addr.s_addr, (char *)server->h_addr_list[0], server->h_length);
     server_addr.sin_family = AF_INET;
     server_addr.sin_port = htons(port);
+    connection.state = UA_CONNECTION_OPENING;
     if(connect(connection.sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
+        ClientNetworkLayerClose(&connection);
         UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Connection failed");
         return connection;
     }
-    connection.state = UA_CONNECTION_OPENING;
     //socket_set_nonblocking(connection.sockfd);
     connection.write = socket_write;
     connection.recv = socket_recv;

+ 3 - 0
examples/networklayer_udp.c

@@ -24,6 +24,9 @@
 # include <sys/ioctl.h>
 # include <unistd.h> // read, write, close
 # include <arpa/inet.h>
+#ifdef __QNX__
+#include <sys/socket.h>
+#endif
 # define CLOSESOCKET(S) close(S)
 
 #define MAXBACKLOG 100

+ 3 - 1
examples/server.c

@@ -182,8 +182,10 @@ static UA_ByteString loadCertificate(void) {
     fseek(fp, 0, SEEK_END);
     certificate.length = ftell(fp);
     certificate.data = malloc(certificate.length*sizeof(UA_Byte));
-	if(!certificate.data)
+	if(!certificate.data){
+		fclose(fp);
 		return certificate;
+	}
 
     fseek(fp, 0, SEEK_SET);
     if(fread(certificate.data, sizeof(UA_Byte), certificate.length, fp) < (size_t)certificate.length)

+ 60 - 13
examples/server_method.c

@@ -19,24 +19,35 @@ UA_Boolean running = UA_TRUE;
 UA_Logger logger;
 
 static UA_StatusCode helloWorldMethod(const UA_NodeId objectId, const UA_Variant *input, UA_Variant *output, void *handle) {
-    UA_String *inputStr = (UA_String*)input->data;
-    UA_String tmp = UA_STRING_ALLOC("Hello ");
-    if(inputStr->length > 0) {
-        tmp.data = realloc(tmp.data, tmp.length + inputStr->length);
-        memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length);
-        tmp.length += inputStr->length;
-    }
-    UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]);
-    UA_String_deleteMembers(&tmp);
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "Hello World was called");
-    return UA_STATUSCODE_GOOD;
+        UA_String *inputStr = (UA_String*)input->data;
+        UA_String tmp = UA_STRING_ALLOC("Hello ");
+        if(inputStr->length > 0) {
+            tmp.data = realloc(tmp.data, tmp.length + inputStr->length);
+            memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length);
+            tmp.length += inputStr->length;
+        }
+        UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]);
+        UA_String_deleteMembers(&tmp);
+        UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "Hello World was called");
+        return UA_STATUSCODE_GOOD;
 } 
 
+static UA_StatusCode IncInt32ArrayValues(const UA_NodeId objectId,
+                                         const UA_Variant *input, UA_Variant *output, void *handle) {
+
+
+	UA_Variant_setArrayCopy(output,input->data,5,&UA_TYPES[UA_TYPES_INT32]);
+	for(int i = 0; i< input->arrayLength; i++){
+		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 2;
+	}
+
+	return UA_STATUSCODE_GOOD;
+}
+
 static void stopHandler(int sign) {
     UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
     running = 0;
 }
-
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
@@ -70,10 +81,46 @@ int main(int argc, char** argv) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             0, 0, &helloWorldMethod, NULL, 1, &inputArguments, 1, &outputArguments, NULL);
 
+    /* add another method node: output argument as 1d Int32 array*/
+    // define input arguments
+    UA_Argument_init(&inputArguments);
+    inputArguments.arrayDimensionsSize = 1;
+    UA_UInt32 * pInputDimensions = UA_UInt32_new();
+    pInputDimensions[0] = 5;
+    inputArguments.arrayDimensions = pInputDimensions;
+    inputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    inputArguments.description = UA_LOCALIZEDTEXT("en_US",
+                    "input an array with 5 elements, type int32");
+    inputArguments.name = UA_STRING("int32 value");
+    inputArguments.valueRank = 1;
+
+    // define output arguments
+    UA_Argument_init(&outputArguments);
+    outputArguments.arrayDimensionsSize = 1;
+    UA_UInt32 * pOutputDimensions = UA_UInt32_new();
+    pOutputDimensions[0] = 5;
+    outputArguments.arrayDimensions = pOutputDimensions;
+    outputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    outputArguments.description = UA_LOCALIZEDTEXT("en_US",
+                    "increment each array index");
+    outputArguments.name = UA_STRING(
+                    "output is the array, each index is incremented");
+    outputArguments.valueRank = 1;
+
+    UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"), UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"),
+                            UA_LOCALIZEDTEXT("en_US","1dArrayExample"), UA_LOCALIZEDTEXT("en_US","1dArrayExample"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), 
+                            0, 0, &IncInt32ArrayValues, NULL, 1, &inputArguments, 1, &outputArguments, NULL);
+
     /* start server */
     UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
 
-    /* ctrl-c received -> clean up */
+        /* ctrl-c received -> clean up */
+    UA_UInt32_delete(pInputDimensions);
+    UA_UInt32_delete(pOutputDimensions);
     UA_Server_delete(server);
+
     return retval;
 }
+
+

+ 1 - 0
examples/server_variable.c

@@ -38,6 +38,7 @@ int main(int argc, char** argv) {
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); /* UA_NODEID_NULL would assign a random free nodeid */
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+
     UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, UA_LOCALIZEDTEXT("en_US",""), UA_LOCALIZEDTEXT("en_US",""),
                               parentNodeId, parentReferenceNodeId, 0, 0, myIntegerVariant, NULL);
 

+ 3 - 0
include/ua_client.h

@@ -31,6 +31,9 @@ typedef struct UA_ClientConfig {
 extern UA_EXPORT const UA_ClientConfig UA_ClientConfig_standard;
 UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config, UA_Logger logger);
 
+UA_EXPORT void UA_Client_reset(UA_Client* client);
+UA_EXPORT void UA_Client_init(UA_Client* client, UA_ClientConfig config, UA_Logger logger);
+UA_EXPORT void UA_Client_deleteMembers(UA_Client* client);
 UA_EXPORT void UA_Client_delete(UA_Client* client);
 
 UA_StatusCode UA_EXPORT UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connFunc, char *endpointUrl);

+ 4 - 0
include/ua_config.h.in

@@ -7,6 +7,8 @@
 
 #define UA_LOGLEVEL ${UA_LOGLEVEL}
 #cmakedefine UA_MULTITHREADING
+#cmakedefine ENABLE_METHODCALLS
+#cmakedefine ENABLE_SUBSCRIPTIONS
 
 /* Function Export */
 #ifdef _WIN32
@@ -33,7 +35,9 @@
 
 /* Endianness */
 #if defined(__linux__) || defined(__APPLE__)
+#  ifndef __QNX__
 # include <endian.h>
+#  endif
 # if ( __BYTE_ORDER != __LITTLE_ENDIAN )
 #  define UA_NON_LITTLEENDIAN_ARCHITECTURE
 # endif

+ 1 - 1
include/ua_types.h

@@ -345,7 +345,7 @@ UA_NodeId UA_EXPORT UA_NodeId_fromByteStringCopy(UA_UInt16 nsIndex, UA_ByteStrin
 #define UA_NODEID_STRING_ALLOC(NSID, CHARS) UA_NodeId_fromCharStringCopy(NSID, CHARS)
 #define UA_NODEID_GUID(NSID, GUID) UA_NodeId_fromGuid(NSID, GUID)
 #define UA_NODEID_BYTESTRING(NSID, CHARS) UA_NodeId_fromCharByteString(NSID, CHARS)
-#define UA_NODEID_BYTESTRING_ALLOC(NSID, CHARS) UA_NodeId_fromCharStringCopy(NSID, CHARS)
+#define UA_NODEID_BYTESTRING_ALLOC(NSID, CHARS) UA_NodeId_fromCharByteStringCopy(NSID, CHARS)
 #define UA_NODEID_NULL UA_NODEID_NUMERIC(0,0)
 
 /* ExpandedNodeId */

+ 82 - 23
src/client/ua_client.c

@@ -6,7 +6,16 @@
 #include "ua_transport_generated.h"
 #include "ua_client_internal.h"
 
+typedef enum {
+       UA_CLIENTSTATE_READY,
+       UA_CLIENTSTATE_CONNECTED,
+       UA_CLIENTSTATE_ERRORED
+} UA_Client_State;
+
 struct UA_Client {
+    /* State */ //maybe it should be visible to user
+    UA_Client_State state;
+
     /* Connection */
     UA_Connection connection;
     UA_SecureChannel channel;
@@ -40,6 +49,18 @@ UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
     if(!client)
         return UA_NULL;
 
+    UA_Client_init(client, config, logger);
+    return client;
+}
+
+void UA_Client_reset(UA_Client* client){
+    UA_Client_deleteMembers(client);
+    UA_Client_init(client, client->config, client->logger);
+}
+
+void UA_Client_init(UA_Client* client, UA_ClientConfig config, UA_Logger logger){
+    client->state = UA_CLIENTSTATE_READY;
+
     UA_Connection_init(&client->connection);
     UA_SecureChannel_init(&client->channel);
     client->channel.connection = &client->connection;
@@ -57,15 +78,21 @@ UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
     LIST_INIT(&client->pendingNotificationsAcks);
     LIST_INIT(&client->subscriptions);
 #endif
-    return client;
 }
 
-void UA_Client_delete(UA_Client* client){
+void UA_Client_deleteMembers(UA_Client* client){
+    if(client->state == UA_CLIENTSTATE_READY) //initialized client has no dynamic memory allocated
+        return;
     UA_Connection_deleteMembers(&client->connection);
     UA_SecureChannel_deleteMembersCleanup(&client->channel);
-    UA_String_deleteMembers(&client->endpointUrl);
+    if(client->endpointUrl.data)
+        UA_String_deleteMembers(&client->endpointUrl);
     UA_UserTokenPolicy_deleteMembers(&client->token);
-    free(client);
+}
+void UA_Client_delete(UA_Client* client){
+    if(client->state != UA_CLIENTSTATE_READY)
+        UA_Client_deleteMembers(client);
+    UA_free(client);
 }
 
 static UA_StatusCode HelAckHandshake(UA_Client *c) {
@@ -258,6 +285,7 @@ static void synchronousRequest(UA_Client *client, void *request, const UA_DataTy
             respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE;
         else
             respHeader->serviceResult = retval;
+        client->state = UA_CLIENTSTATE_ERRORED;
         return;
     }
 
@@ -269,6 +297,7 @@ static void synchronousRequest(UA_Client *client, void *request, const UA_DataTy
         retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
         if(retval != UA_STATUSCODE_GOOD) {
             respHeader->serviceResult = retval;
+            client->state = UA_CLIENTSTATE_ERRORED;
             return;
         }
     } while(!reply.data);
@@ -308,8 +337,10 @@ static void synchronousRequest(UA_Client *client, void *request, const UA_DataTy
  finish:
     UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
     UA_ByteString_deleteMembers(&reply);
-    if(retval != UA_STATUSCODE_GOOD)
+    if(retval != UA_STATUSCODE_GOOD){
+        client->state = UA_CLIENTSTATE_ERRORED;
         respHeader->serviceResult = retval;
+    }
 }
 
 static UA_StatusCode ActivateSession(UA_Client *client) {
@@ -489,16 +520,30 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
 /*************************/
 
 UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc, char *endpointUrl) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+
+    /** make the function more convenient to the end-user **/
+    if(client->state == UA_CLIENTSTATE_CONNECTED){
+        UA_Client_disconnect(client);
+    }
+    if(client->state == UA_CLIENTSTATE_ERRORED){
+        UA_Client_reset(client);
+    }
+
     client->connection = connectFunc(UA_ConnectionConfig_standard, endpointUrl, &client->logger);
-    if(client->connection.state != UA_CONNECTION_OPENING)
-        return UA_STATUSCODE_BADCONNECTIONCLOSED;
+    if(client->connection.state != UA_CONNECTION_OPENING){
+        retval = UA_STATUSCODE_BADCONNECTIONCLOSED;
+        goto cleanup;
+    }
 
     client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
-    if(client->endpointUrl.length < 0)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+    if(client->endpointUrl.length < 0){
+        retval = UA_STATUSCODE_BADOUTOFMEMORY;
+        goto cleanup;
+    }
 
     client->connection.localConf = client->config.localConnectionConfig;
-    UA_StatusCode retval = HelAckHandshake(client);
+    retval = HelAckHandshake(client);
     if(retval == UA_STATUSCODE_GOOD)
         retval = SecureChannelHandshake(client, UA_FALSE);
     if(retval == UA_STATUSCODE_GOOD)
@@ -507,18 +552,28 @@ UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection co
         retval = SessionHandshake(client);
     if(retval == UA_STATUSCODE_GOOD)
         retval = ActivateSession(client);
-    if(retval == UA_STATUSCODE_GOOD)
+    if(retval == UA_STATUSCODE_GOOD){
         client->connection.state = UA_CONNECTION_ESTABLISHED;
+        client->state = UA_CLIENTSTATE_CONNECTED;
+    }else{
+        goto cleanup;
+    }
     return retval;
+
+    cleanup:
+        client->state = UA_CLIENTSTATE_ERRORED;
+        UA_Client_reset(client);
+        return retval;
 }
 
 UA_StatusCode UA_Client_disconnect(UA_Client *client) {
-    UA_StatusCode retval;
-    if(client->channel.connection->state != UA_CONNECTION_ESTABLISHED)
-        return UA_STATUSCODE_GOOD;
-    retval = CloseSession(client);
-    if(retval == UA_STATUSCODE_GOOD)
-        retval = CloseSecureChannel(client);
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(client->channel.connection->state == UA_CONNECTION_ESTABLISHED){
+        retval = CloseSession(client);
+        if(retval == UA_STATUSCODE_GOOD)
+            retval = CloseSecureChannel(client);
+    }
+    UA_Client_reset(client);
     return retval;
 }
 
@@ -693,12 +748,14 @@ UA_StatusCode UA_Client_removeSubscription(UA_Client *client, UA_UInt32 subscrip
     request.subscriptionIds = (UA_UInt32 *) UA_malloc(sizeof(UA_UInt32));
     *(request.subscriptionIds) = sub->SubscriptionID;
     
-    UA_Client_MonitoredItem *mon;
-    LIST_FOREACH(mon, &(sub->MonitoredItems), listEntry) {
+    UA_Client_MonitoredItem *mon, *tmpmon;
+    LIST_FOREACH_SAFE(mon, &(sub->MonitoredItems), listEntry, tmpmon) {
         retval |= UA_Client_unMonitorItemChanges(client, sub->SubscriptionID, mon->MonitoredItemId);
     }
-    if (retval != UA_STATUSCODE_GOOD)
+    if (retval != UA_STATUSCODE_GOOD){
+	    UA_DeleteSubscriptionsRequest_deleteMembers(&request);
         return retval;
+    }
     
     response = UA_Client_deleteSubscriptions(client, &request);
     
@@ -791,8 +848,8 @@ UA_StatusCode UA_Client_unMonitorItemChanges(UA_Client *client, UA_UInt32 subscr
     if (sub == NULL)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
     
-    UA_Client_MonitoredItem *mon;
-    LIST_FOREACH(mon, &(sub->MonitoredItems), listEntry) {
+    UA_Client_MonitoredItem *mon, *tmpmon;
+    LIST_FOREACH_SAFE(mon, &(sub->MonitoredItems), listEntry, tmpmon) {
         if (mon->MonitoredItemId == monitoredItemId)
             break;
     }
@@ -819,6 +876,7 @@ UA_StatusCode UA_Client_unMonitorItemChanges(UA_Client *client, UA_UInt32 subscr
     
     if (retval == 0) {
         LIST_REMOVE(mon, listEntry);
+        UA_NodeId_deleteMembers(&mon->monitoredNodeId);
         UA_free(mon);
     }
     
@@ -879,6 +937,7 @@ UA_Boolean UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse resp
                         }
                     }
                 }
+                UA_DataChangeNotification_deleteMembers(&dataChangeNotification);
             }
             else if (msg.notificationData[k].typeId.namespaceIndex == 0 && msg.notificationData[k].typeId.identifier.numeric == 820 ) {
                 //FIXME: This is a statusChangeNotification (not supported yet)
@@ -1976,4 +2035,4 @@ UA_Client_getAttributeValue(UA_Client *client, UA_NodeId nodeId, UA_AttributeId
   
   UA_ReadResponse_deleteMembers(&rrs);
   return retval;
-}
+}

+ 13 - 5
src/server/ua_server_addressspace.c

@@ -175,7 +175,8 @@ UA_Server_addVariableNode(UA_Server *server, UA_NodeId nodeId, const UA_Qualifie
     if (createdNodeId != UA_NULL)
       UA_NodeId_copy(&res.addedNodeId, createdNodeId);
     UA_AddNodesResult_deleteMembers(&res);
-    return retval ;
+    UA_ExpandedNodeId_deleteMembers(&parentId);
+    return retval;
 }
 
 UA_StatusCode
@@ -797,6 +798,7 @@ UA_Server_addMethodNode(UA_Server* server, UA_NodeId nodeId, const UA_QualifiedN
     
     if (createdNodeId != UA_NULL)
       UA_NodeId_copy(&addRes.addedNodeId, createdNodeId);
+    UA_AddNodesResult_deleteMembers(&addRes);
     
     /* Only proceed with creating in/outputArguments if the method and both arguments are not
      * UA_NULL; otherwise this is a pretty strong indicator that this node was generated,
@@ -819,12 +821,13 @@ UA_Server_addMethodNode(UA_Server* server, UA_NodeId nodeId, const UA_QualifiedN
                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
     if(addRes.statusCode != UA_STATUSCODE_GOOD) {
         UA_ExpandedNodeId_deleteMembers(&methodExpandedNodeId);
+        if(createdNodeId != UA_NULL)
+            UA_NodeId_deleteMembers(createdNodeId);    	
         // TODO Remove node
         return addRes.statusCode;
     }
-    if (createdNodeId != UA_NULL)
-      UA_NodeId_copy(&addRes.addedNodeId, createdNodeId);
-    
+    UA_AddNodesResult_deleteMembers(&addRes);
+
     /* create OutputArguments */
     argId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0);
     UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
@@ -839,8 +842,13 @@ UA_Server_addMethodNode(UA_Server* server, UA_NodeId nodeId, const UA_QualifiedN
                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
     UA_ExpandedNodeId_deleteMembers(&methodExpandedNodeId);
     if(addRes.statusCode != UA_STATUSCODE_GOOD)
+    {
+        if(createdNodeId != UA_NULL)
+            UA_NodeId_deleteMembers(createdNodeId);    	
         // TODO Remove node
         retval = addRes.statusCode;
+    }
+    UA_AddNodesResult_deleteMembers(&addRes);
     return retval;
 }
 
@@ -1501,4 +1509,4 @@ UA_StatusCode UA_Server_addInstanceOf(UA_Server *server, UA_NodeId nodeId, const
   UA_ExpandedNodeId_delete(objectRootExpanded);
   UA_Server_deleteNodeCopy(server, (void **) &typeDefNode);
   return retval;
-}
+}

+ 18 - 5
src/server/ua_server_worker.c

@@ -22,6 +22,16 @@
  * - Remove the entry from the list
  * - mark it as "dead" with an atomic operation
  * - add a delayed job that frees the memory when all concurrent operations have completed
+ * 
+ * This approach to concurrently accessible memory is known as epoch based reclamation [1]. According to
+ * [2], it performs competitively well on many-core systems. Our version of EBR does however not require
+ * a global epoch. Instead, every worker thread has its own epoch counter that we observe for changes.
+ * 
+ * [1] Fraser, K. 2003. Practical lock freedom. Ph.D. thesis. Computer Laboratory, University of Cambridge.
+ * [2] Hart, T. E., McKenney, P. E., Brown, A. D., & Walpole, J. (2007). Performance of memory reclamation
+ *     for lockless synchronization. Journal of Parallel and Distributed Computing, 67(12), 1270-1285.
+ * 
+ * 
  */
 
 #define MAXTIMEOUT 50000 // max timeout in microsec until the next main loop iteration
@@ -511,6 +521,8 @@ static void processMainLoopJobs(UA_Server *server) {
 #endif
 
 UA_StatusCode UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running) {
+UA_StatusCode result = UA_STATUSCODE_GOOD;
+
 #ifdef UA_MULTITHREADING
     /* Prepare the worker threads */
     server->running = running; // the threads need to access the variable
@@ -533,9 +545,9 @@ UA_StatusCode UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Bo
 
     /* Start the networklayers */
     for(size_t i = 0; i < server->networkLayersSize; i++)
-        server->networkLayers[i].start(&server->networkLayers[i], &server->logger);
+        result |= server->networkLayers[i].start(&server->networkLayers[i], &server->logger);
 
-    return UA_STATUSCODE_GOOD;
+    return result;
 }
 
 UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
@@ -610,9 +622,10 @@ UA_StatusCode UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads){
 }
 
 UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running) {
-    UA_Server_run_startup(server, nThreads, running);
-    while(*running) {
-        UA_Server_run_mainloop(server, running);
+    if(UA_STATUSCODE_GOOD == UA_Server_run_startup(server, nThreads, running)){
+        while(*running) {
+            UA_Server_run_mainloop(server, running);
+        }
     }
     UA_Server_run_shutdown(server, nThreads);
     return UA_STATUSCODE_GOOD;

+ 12 - 4
src/server/ua_services_call.c

@@ -50,18 +50,26 @@ static UA_StatusCode statisfySignature(UA_Variant *var, UA_Argument arg) {
             return UA_STATUSCODE_BADINVALIDARGUMENT;
         if(arg.valueRank == -3 && var->arrayDimensionsSize > 1)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
-        if(arg.valueRank >= 1 && var->arrayDimensionsSize != arg.arrayDimensionsSize)
+        if(arg.valueRank > 1 && var->arrayDimensionsSize != arg.arrayDimensionsSize)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
         
-        if(arg.arrayDimensionsSize >= 1) {
+        //variants do not always encode the dimension flag (e.g. 1d array)
+       if(var->arrayDimensionsSize==-1 && arg.arrayDimensionsSize == 1 &&
+    		   var->arrayLength > 0 && arg.arrayDimensions[0] == (UA_UInt32)var->arrayLength ){
+    	   return UA_STATUSCODE_GOOD;
+       }else{
+         if(arg.valueRank >= 1 && var->arrayDimensionsSize != arg.arrayDimensionsSize)
+            return UA_STATUSCODE_BADINVALIDARGUMENT;
+         if(arg.arrayDimensionsSize >= 1) {
             if(arg.arrayDimensionsSize != var->arrayDimensionsSize)
                 return UA_STATUSCODE_BADINVALIDARGUMENT;
             for(UA_Int32 i = 0; i < arg.arrayDimensionsSize; i++) {
                 if(arg.arrayDimensions[i] != (UA_UInt32) var->arrayDimensions[i])
                     return UA_STATUSCODE_BADINVALIDARGUMENT;
             }
-        }
-   return UA_STATUSCODE_GOOD;
+         }
+    }
+    return UA_STATUSCODE_GOOD;
 }
 
 static UA_StatusCode argConformsToDefinition(UA_CallMethodRequest *rs, const UA_VariableNode *argDefinition) {

+ 2 - 3
src/server/ua_services_nodemanagement.c

@@ -5,14 +5,13 @@
 #include "ua_session.h"
 #include "ua_util.h"
 
-#define COPY_STANDARDATTRIBUTES do {                                       \
+#define COPY_STANDARDATTRIBUTES do {  \
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) {     \
         vnode->displayName = attr.displayName;                             \
-        UA_LocalizedText_copy(&attr.displayName, &(vnode->displayName));   \
         UA_LocalizedText_init(&attr.displayName);                          \
     }                                                                      \
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DESCRIPTION) {     \
-        UA_LocalizedText_copy(&attr.description, &(vnode->description));   \
+        vnode->description = attr.description;                             \
         UA_LocalizedText_init(&attr.description);                          \
     }                                                                      \
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_WRITEMASK)         \

+ 1 - 1
src/server/ua_services_subscription.c

@@ -191,7 +191,7 @@ void Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishReq
     // subscriptions have notifications, force one to generate a keepalive so we
     // don't return an empty message
     sub = LIST_FIRST(&manager->serverSubscriptions);
-    if(!sub) {
+    if(sub) {
         response->subscriptionId = sub->subscriptionID;
         sub->keepAliveCount.currentValue=sub->keepAliveCount.minValue;
         Subscription_generateKeepAlive(sub);

+ 3 - 5
src/server/ua_subscription.c

@@ -37,7 +37,6 @@ void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *ser
     
     // Delete unpublished Notifications
     LIST_FOREACH_SAFE(not, &subscription->unpublishedNotifications, listEntry, tmp_not) {
-        LIST_REMOVE(not, listEntry);
         Subscription_deleteUnpublishedNotification(not->notification->sequenceNumber, subscription);
     }
     
@@ -81,7 +80,7 @@ void Subscription_generateKeepAlive(UA_Subscription *subscription) {
 void Subscription_updateNotifications(UA_Subscription *subscription) {
     UA_MonitoredItem *mon;
     //MonitoredItem_queuedValue *queuedValue;
-    UA_unpublishedNotification *msg = NULL;
+    UA_unpublishedNotification *msg = NULL, *tempmsg;
     UA_UInt32 monItemsChangeT = 0, monItemsStatusT = 0, monItemsEventT = 0;
     UA_DataChangeNotification *changeNotification;
     size_t notificationOffset;
@@ -106,9 +105,8 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
     // FIXME: This is hardcoded to 100 because it is not covered by the spec but we need to protect the server!
     if(Subscription_queuedNotifications(subscription) >= 10) {
         // Remove last entry
-        LIST_FOREACH(msg, &subscription->unpublishedNotifications, listEntry)
-            LIST_REMOVE(msg, listEntry);
-        UA_free(msg);
+        LIST_FOREACH_SAFE(msg, &subscription->unpublishedNotifications, listEntry, tempmsg)
+            Subscription_deleteUnpublishedNotification(msg->notification->sequenceNumber, subscription);
     }
     
     if(monItemsChangeT == 0 && monItemsEventT == 0 && monItemsStatusT == 0) {

+ 21 - 23
src/ua_types_encoding_binary.c

@@ -791,7 +791,7 @@ UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst,
 
 /* The resulting variant always has the storagetype UA_VARIANT_DATA. Currently,
  we only support ns0 types (todo: attach typedescriptions to datatypenodes) */
-UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset, UA_Variant *dst) {
+UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Variant *dst) {
     UA_Variant_init(dst);
     UA_Byte encodingByte;
     UA_StatusCode retval = UA_Byte_decodeBinary(src, offset, &encodingByte);
@@ -803,38 +803,34 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTR
     if(typeIndex > 24) /* must be builtin */
         return UA_STATUSCODE_BADDECODINGERROR;
 
-    if(isArray) {
+    if(isArray || typeIndex != UA_TYPES_EXTENSIONOBJECT) {
+        /* an array or a single builtin */
         const UA_DataType *dataType = &UA_TYPES[typeIndex];
         UA_Int32 arraySize = -1;
-        retval |= UA_Int32_decodeBinary(src, offset, &arraySize);
-        retval |= UA_Array_decodeBinary(src, offset, arraySize, &dst->data, dataType);
-        if(retval != UA_STATUSCODE_GOOD)
-            return retval;
-        dst->arrayLength = arraySize;
-        dst->type = dataType;
-    } else if(typeIndex != UA_TYPES_EXTENSIONOBJECT) {
-        const UA_DataType *dataType = &UA_TYPES[typeIndex];
-        retval |= UA_Array_decodeBinary(src, offset, 1, &dst->data, dataType);
+        if(isArray) {
+            retval |= UA_Int32_decodeBinary(src, offset, &arraySize);
+            if(retval != UA_STATUSCODE_GOOD)
+                return retval;
+        }
+        retval |= UA_Array_decodeBinary(src, offset, (!isArray && arraySize==-1) ? 1: arraySize, &dst->data, dataType);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
+        dst->arrayLength = arraySize; // for deleteMembers
         dst->type = dataType;
     } else {
         /* a single extensionobject */
         size_t oldoffset = *offset;
         UA_NodeId typeId;
-        retval = UA_NodeId_decodeBinary(src, offset, &typeId);
-        if(retval != UA_STATUSCODE_GOOD)
+        if((retval |= UA_NodeId_decodeBinary(src, offset, &typeId)) != UA_STATUSCODE_GOOD)
             return retval;
         UA_Byte EOencodingByte;
-        retval = UA_Byte_decodeBinary(src, offset, &EOencodingByte);
-        if(retval != UA_STATUSCODE_GOOD) {
+        if((retval |= UA_Byte_decodeBinary(src, offset, &EOencodingByte)) != UA_STATUSCODE_GOOD) {
             UA_NodeId_deleteMembers(&typeId);
             return retval;
         }
         const UA_DataType *dataType = UA_NULL;
         if(typeId.namespaceIndex == 0 && EOencodingByte == UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING) {
-            /* find the datatype (ins ns0) of the extension object */
-            for(typeIndex = 0; typeIndex < UA_TYPES_COUNT; typeIndex++) {
+            for(typeIndex = 0;typeIndex < UA_TYPES_COUNT; typeIndex++) {
                 if(UA_NodeId_equal(&typeId, &UA_TYPES[typeIndex].typeId)) {
                     dataType = &UA_TYPES[typeIndex];
                     break;
@@ -846,8 +842,8 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTR
             *offset = oldoffset;
             dataType = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
         }
-        retval = UA_decodeBinary(src, offset, dst->data, dataType);
-        if(retval != UA_STATUSCODE_GOOD)
+        dst->data = UA_malloc(dataType->memSize);
+        if((retval |= UA_decodeBinary(src, offset, dst->data, dataType)) != UA_STATUSCODE_GOOD)
             return retval;
         dst->type = dataType;
         dst->arrayLength = -1;
@@ -855,15 +851,17 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTR
 
     /* array dimensions */
     if(isArray && (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS)) {
-        retval = UA_Int32_decodeBinary(src, offset, &dst->arrayDimensionsSize);
-        retval |= UA_Array_decodeBinary(src, offset, dst->arrayDimensionsSize,(void**) &dst->arrayDimensions,
-                                        &UA_TYPES[UA_TYPES_INT32]);
+        retval |= UA_Int32_decodeBinary(src, offset, &dst->arrayDimensionsSize);
+        if(retval == UA_STATUSCODE_GOOD)
+            retval |= UA_Array_decodeBinary(src, offset, dst->arrayDimensionsSize,
+                                            &dst->data, &UA_TYPES[UA_TYPES_INT32]);
         if(retval != UA_STATUSCODE_GOOD) {
             dst->arrayDimensionsSize = -1;
             UA_Variant_deleteMembers(dst);
+            return retval;
         }
     }
-    return retval;
+    return UA_STATUSCODE_GOOD;
 }
 
 /* DiagnosticInfo */

+ 6 - 0
tests/CMakeLists.txt

@@ -47,6 +47,12 @@ add_executable(check_nodestore check_nodestore.c $<TARGET_OBJECTS:open62541-obje
 target_link_libraries(check_nodestore ${LIBS})
 add_test(nodestore ${CMAKE_CURRENT_BINARY_DIR}/check_nodestore)
 
+
+
+add_executable(check_session check_session.c $<TARGET_OBJECTS:open62541-object>)
+target_link_libraries(check_session ${LIBS})
+add_test(session ${CMAKE_CURRENT_BINARY_DIR}/check_session)
+
 # add_executable(check_startup check_startup.c)
 # target_link_libraries(check_startup ${LIBS})
 # add_test(startup ${CMAKE_CURRENT_BINARY_DIR}/check_startup)

+ 56 - 0
tests/check_builtin.c

@@ -727,6 +727,61 @@ START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray)
 }
 END_TEST
 
+START_TEST(UA_Variant_decodeSingleExtensionObjectShallSetVTAndAllocateMemory){
+    // given
+    size_t pos = 0;
+    UA_Variant dst;
+    UA_NodeId tmpNodeId;
+    UA_ByteString srcByteString;
+
+    UA_NodeId_init(&tmpNodeId);
+    tmpNodeId.identifier.numeric = 22;
+    tmpNodeId.namespaceIndex = 2;
+    tmpNodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
+
+    UA_ExtensionObject tmpExtensionObject;
+    UA_ExtensionObject_init(&tmpExtensionObject);
+    UA_ByteString_newMembers(&tmpExtensionObject.body,3);
+    tmpExtensionObject.body.data[0]= 10;
+    tmpExtensionObject.body.data[1]= 20;
+    tmpExtensionObject.body.data[2]= 30;
+    tmpExtensionObject.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
+    tmpExtensionObject.typeId = tmpNodeId;
+
+    UA_Variant tmpVariant;
+    UA_Variant_init(&tmpVariant);
+    tmpVariant.arrayDimensions = UA_NULL;
+    tmpVariant.arrayDimensionsSize = -1;
+    tmpVariant.arrayLength = -1;
+    tmpVariant.storageType = UA_VARIANT_DATA_NODELETE;
+    tmpVariant.type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
+    tmpVariant.data = &tmpExtensionObject;
+
+    UA_ByteString_newMembers(&srcByteString,200);
+    pos = 0;
+    UA_Variant_encodeBinary(&tmpVariant,&srcByteString,&pos);
+
+    // when
+    pos = 0;
+    UA_StatusCode retval = UA_Variant_decodeBinary(&srcByteString, &pos, &dst);
+    // then
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+    ck_assert_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
+    ck_assert_int_eq(dst.arrayLength, -1);
+    ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.data[0], 10);
+    ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.data[1], 20);
+    ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.data[2], 30);
+    ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.length, 3);
+
+
+    // finally
+    UA_Variant_deleteMembers(&dst);
+    UA_ByteString_deleteMembers(&srcByteString);
+    UA_ExtensionObject_deleteMembers(&tmpExtensionObject);
+
+}
+END_TEST
+
 START_TEST(UA_Variant_decodeWithOutDeleteMembersShallFailInCheckMem) {
     // given
     size_t pos = 0;
@@ -1710,6 +1765,7 @@ static Suite *testSuite_builtin(void) {
     tcase_add_test(tc_decode, UA_NodeId_decodeTwoByteShallReadTwoBytesAndSetNamespaceToZero);
     tcase_add_test(tc_decode, UA_NodeId_decodeFourByteShallReadFourBytesAndRespectNamespace);
     tcase_add_test(tc_decode, UA_NodeId_decodeStringShallAllocateMemory);
+    tcase_add_test(tc_decode, UA_Variant_decodeSingleExtensionObjectShallSetVTAndAllocateMemory);
     tcase_add_test(tc_decode, UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArray);
     tcase_add_test(tc_decode, UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray);
     tcase_add_test(tc_decode, UA_Variant_decodeWithOutDeleteMembersShallFailInCheckMem);

+ 1 - 1
tests/check_services_attributes.c

@@ -377,7 +377,7 @@ START_TEST(ReadSingleAttributeInverseNameWithoutTimestamp)
 
 		UA_LocalizedText* respval;
 		respval = (UA_LocalizedText*) resp.value.data;
-		const UA_LocalizedText comp = UA_LOCALIZEDTEXT("", "OrganizedBy");
+		const UA_LocalizedText comp = UA_LOCALIZEDTEXT("en_US", "OrganizedBy");
 
 		ck_assert_int_eq(-1, resp.value.arrayLength);
 		ck_assert_int_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT],resp.value.type);

+ 92 - 0
tests/check_session.c

@@ -0,0 +1,92 @@
+/*
+ * check_session.c
+ *
+ *  Created on: Jul 30, 2015
+ *      Author: opcua
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ua_types.h"
+#include "server/ua_services.h"
+#include "ua_statuscodes.h"
+#include "check.h"
+#include "ua_util.h"
+
+
+START_TEST(Session_init_ShallWork)
+{
+	UA_Session session;
+	UA_Session_init(&session);
+
+
+    UA_NodeId tmpNodeId;
+    UA_NodeId_init(&tmpNodeId);
+    UA_ApplicationDescription tmpAppDescription;
+    UA_ApplicationDescription_init(&tmpAppDescription);
+    UA_DateTime tmpDateTime;
+    UA_DateTime_init(&tmpDateTime);
+	ck_assert_int_eq(session.activated,UA_FALSE);
+	ck_assert_int_eq(session.authenticationToken.identifier.numeric,tmpNodeId.identifier.numeric);
+	ck_assert_int_eq(session.availableContinuationPoints,MAXCONTINUATIONPOINTS);
+    ck_assert_int_eq(session.channel,UA_NULL);
+    ck_assert_int_eq(session.clientDescription.applicationName.locale.data,UA_NULL);
+    ck_assert_int_eq(session.continuationPoints.lh_first, UA_NULL);
+    ck_assert_int_eq(session.maxRequestMessageSize,0);
+    ck_assert_int_eq(session.maxResponseMessageSize,0);
+    ck_assert_int_eq(session.sessionId.identifier.numeric,tmpNodeId.identifier.numeric);
+    ck_assert_int_eq(session.sessionName.data,UA_NULL);
+    ck_assert_int_eq(session.timeout,0);
+    ck_assert_int_eq(session.validTill,tmpDateTime);
+
+
+	//finally
+}
+END_TEST
+
+START_TEST(Session_updateLifetime_ShallWork)
+{
+	UA_Session session;
+	UA_Session_init(&session);
+    UA_DateTime tmpDateTime;
+    tmpDateTime = session.validTill;
+	UA_Session_updateLifetime(&session);
+
+	UA_Int32 result = (session.validTill > tmpDateTime);
+
+	ck_assert_int_gt(result,0);
+
+
+
+	//finally
+}
+END_TEST
+
+static Suite* testSuite_Session(void) {
+	Suite *s = suite_create("Session");
+	TCase *tc_core = tcase_create("Core");
+	tcase_add_test(tc_core, Session_init_ShallWork);
+	tcase_add_test(tc_core, Session_updateLifetime_ShallWork);
+
+	suite_add_tcase(s,tc_core);
+	return s;
+}
+
+int main(void) {
+	int number_failed = 0;
+
+	Suite *s;
+	SRunner *sr;
+
+	s = testSuite_Session();
+	sr = srunner_create(s);
+	srunner_run_all(sr,CK_NORMAL);
+	number_failed += srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+