Julius Pfrommer преди 7 години
родител
ревизия
50b1f3dfaf

+ 76 - 113
src/client/ua_client.c

@@ -4,35 +4,15 @@
 
 #include "ua_util.h"
 #include "ua_client.h"
-#include "ua_client_highlevel.h"
 #include "ua_client_internal.h"
 #include "ua_connection_internal.h"
-#include "ua_types_generated.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_generated_encoding_binary.h"
-#include "ua_nodeids.h"
 #include "ua_transport_generated.h"
 #include "ua_transport_generated_handling.h"
 #include "ua_transport_generated_encoding_binary.h"
-
-/* Listen with a timeout until at least one complete message is received */
-static UA_StatusCode
-Connection_receiveChunk(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
-                        UA_Boolean * UA_RESTRICT realloced, UA_UInt32 timeout) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    *realloced = false;
-    UA_DateTime maxDate = UA_DateTime_nowMonotonic() + (timeout * UA_MSEC_TO_DATETIME);
-    /* Receive packets until one complete message is assembled */
-    do {
-        UA_DateTime now = UA_DateTime_nowMonotonic();
-        if(now > maxDate)
-            return UA_STATUSCODE_GOODNONCRITICALTIMEOUT;
-        UA_UInt32 thisTimeout = (UA_UInt32)((maxDate - now) / UA_MSEC_TO_DATETIME);
-        retval = connection->recv(connection, message, thisTimeout);
-        retval |= UA_Connection_completeMessages(connection, message, realloced);
-    } while(retval == UA_STATUSCODE_GOOD && message->length == 0);
-    return retval;
-}
+#include "ua_util.h"
+#include "ua_nodeids.h"
 
 /*********************/
 /* Create and Delete */
@@ -40,36 +20,22 @@ Connection_receiveChunk(UA_Connection *connection, UA_ByteString * UA_RESTRICT m
 
 static void UA_Client_init(UA_Client* client, UA_ClientConfig config) {
     memset(client, 0, sizeof(UA_Client));
-
-    client->state = UA_CLIENTSTATE_READY;
-    client->connection = (UA_Connection*)UA_malloc(sizeof(UA_Connection));
-    memset(client->connection, 0, sizeof(UA_Connection));
-    client->channel = (UA_SecureChannel*)UA_malloc(sizeof(UA_SecureChannel));
-    UA_SecureChannel_init(client->channel);
-    client->channel->connection = client->connection;
-    client->authenticationMethod = UA_CLIENTAUTHENTICATION_NONE;
+    client->channel.connection = &client->connection;
     client->config = config;
-#ifdef UA_ENABLE_SUBSCRIPTIONS
-    LIST_INIT(&client->pendingNotificationsAcks);
-    LIST_INIT(&client->subscriptions);
-#endif
 }
 
 UA_Client * UA_Client_new(UA_ClientConfig config) {
     UA_Client *client = (UA_Client*)UA_calloc(1, sizeof(UA_Client));
     if(!client)
         return NULL;
-
     UA_Client_init(client, config);
     return client;
 }
 
 static void UA_Client_deleteMembers(UA_Client* client) {
     UA_Client_disconnect(client);
-    UA_SecureChannel_deleteMembersCleanup(client->channel);
-    UA_free(client->channel);
-    UA_Connection_deleteMembers(client->connection);
-    UA_free(client->connection);
+    UA_SecureChannel_deleteMembersCleanup(&client->channel);
+    UA_Connection_deleteMembers(&client->connection);
     if(client->endpointUrl.data)
         UA_String_deleteMembers(&client->endpointUrl);
     UA_UserTokenPolicy_deleteMembers(&client->token);
@@ -113,13 +79,10 @@ UA_ClientState UA_EXPORT UA_Client_getState(UA_Client *client) {
 #define UA_MINMESSAGESIZE 8192
 
 static UA_StatusCode HelAckHandshake(UA_Client *client) {
-    UA_Connection *conn = client->connection;
-
     /* Get a buffer */
     UA_ByteString message;
-    UA_StatusCode retval =
-        client->connection->getSendBuffer(client->connection,
-                                          UA_MINMESSAGESIZE, &message);
+    UA_Connection *conn = &client->connection;
+    UA_StatusCode retval = conn->getSendBuffer(conn, UA_MINMESSAGESIZE, &message);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
@@ -143,13 +106,13 @@ static UA_StatusCode HelAckHandshake(UA_Client *client) {
     offset = 0;
     retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &message, &offset);
     if(retval != UA_STATUSCODE_GOOD) {
-        client->connection->releaseSendBuffer(client->connection, &message);
+        conn->releaseSendBuffer(conn, &message);
         return retval;
     }
 
     /* Send the HEL message */
     message.length = messageHeader.messageSize;
-    retval = client->connection->send(client->connection, &message);
+    retval = conn->send(conn, &message);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK,
                     "Sending HEL failed");
@@ -161,8 +124,8 @@ static UA_StatusCode HelAckHandshake(UA_Client *client) {
     /* Loop until we have a complete chunk */
     UA_ByteString reply = UA_BYTESTRING_NULL;
     UA_Boolean realloced = false;
-    retval = Connection_receiveChunk(client->connection, &reply,
-                                     &realloced, client->config.timeout);
+    retval = UA_Connection_receiveChunksBlocking(conn, &reply, &realloced,
+                                                 client->config.timeout);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK,
                     "Receiving ACK message failed");
@@ -177,15 +140,14 @@ static UA_StatusCode HelAckHandshake(UA_Client *client) {
 
     /* Free the message buffer */
     if(!realloced)
-        client->connection->releaseRecvBuffer(client->connection, &reply);
+        conn->releaseRecvBuffer(conn, &reply);
     else
         UA_ByteString_deleteMembers(&reply);
 
     /* Store remote connection settings and adjust local configuration to not
        exceed the limits */
     if(retval == UA_STATUSCODE_GOOD) {
-        UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_NETWORK,
-                     "Received ACK message");
+        UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_NETWORK, "Received ACK message");
         conn->remoteConf.maxChunkCount = ackMessage.maxChunkCount; /* may be zero -> unlimited */
         conn->remoteConf.maxMessageSize = ackMessage.maxMessageSize; /* may be zero -> unlimited */
         conn->remoteConf.protocolVersion = ackMessage.protocolVersion;
@@ -197,8 +159,7 @@ static UA_StatusCode HelAckHandshake(UA_Client *client) {
             conn->localConf.recvBufferSize = conn->remoteConf.sendBufferSize;
         conn->state = UA_CONNECTION_ESTABLISHED;
     } else {
-        UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK,
-                    "Decoding ACK message failed");
+        UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK, "Decoding ACK message failed");
     }
     UA_TcpAcknowledgeMessage_deleteMembers(&ackMessage);
 
@@ -208,23 +169,23 @@ static UA_StatusCode HelAckHandshake(UA_Client *client) {
 static UA_StatusCode
 SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
     /* Check if sc is still valid */
-    if(renew && client->scRenewAt - UA_DateTime_now() > 0)
+    if(renew && client->nextChannelRenewal - UA_DateTime_nowMonotonic() > 0)
         return UA_STATUSCODE_GOOD;
 
-    UA_Connection *c = client->connection;
-    if(c->state != UA_CONNECTION_ESTABLISHED)
+    UA_Connection *conn = &client->connection;
+    if(conn->state != UA_CONNECTION_ESTABLISHED)
         return UA_STATUSCODE_BADSERVERNOTCONNECTED;
 
     UA_SecureConversationMessageHeader messageHeader;
     messageHeader.messageHeader.messageTypeAndChunkType =
         UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL;
     if(renew)
-        messageHeader.secureChannelId = client->channel->securityToken.channelId;
+        messageHeader.secureChannelId = client->channel.securityToken.channelId;
     else
         messageHeader.secureChannelId = 0;
 
     UA_SequenceHeader seqHeader;
-    seqHeader.sequenceNumber = ++client->channel->sendSequenceNumber;
+    seqHeader.sequenceNumber = ++client->channel.sendSequenceNumber;
     seqHeader.requestId = ++client->requestId;
 
     UA_AsymmetricAlgorithmSecurityHeader asymHeader;
@@ -251,11 +212,11 @@ SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
                      "Requesting to open a SecureChannel");
     }
 
-    UA_ByteString_copy(&client->channel->clientNonce, &opnSecRq.clientNonce);
+    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);
+    UA_StatusCode retval = conn->getSendBuffer(conn, conn->remoteConf.recvBufferSize, &message);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
@@ -274,18 +235,19 @@ SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
     UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
     if(retval != UA_STATUSCODE_GOOD) {
-        client->connection->releaseSendBuffer(client->connection, &message);
+        client->connection.releaseSendBuffer(&client->connection, &message);
         return retval;
     }
 
     message.length = messageHeader.messageHeader.messageSize;
-    retval = client->connection->send(client->connection, &message);
+    retval = conn->send(conn, &message);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
     UA_ByteString reply = UA_BYTESTRING_NULL;
     UA_Boolean realloced = false;
-    retval = Connection_receiveChunk(c, &reply, &realloced, client->config.timeout);
+    retval = UA_Connection_receiveChunksBlocking(conn, &reply, &realloced,
+                                                 client->config.timeout);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                      "Receiving OpenSecureChannelResponse failed");
@@ -310,7 +272,7 @@ SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
     }
 
     /* Save the sequence number from server */
-    client->channel->receiveSequenceNumber = seqHeader.sequenceNumber;
+    client->channel.receiveSequenceNumber = seqHeader.sequenceNumber;
 
     /* Decode the response */
     UA_OpenSecureChannelResponse response;
@@ -318,45 +280,44 @@ SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
 
     /* Free the message */
     if(!realloced)
-        c->releaseRecvBuffer(c, &reply);
+        conn->releaseRecvBuffer(conn, &reply);
     else
         UA_ByteString_deleteMembers(&reply);
 
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
-                     "Decoding OpenSecureChannelResponse failed");
-        UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
-        UA_OpenSecureChannelResponse_init(&response);
-        response.responseHeader.serviceResult = retval;
-        return retval;
-    }
+    /* Results in either the StatusCode of decoding or the service */
+    retval |= response.responseHeader.serviceResult;
 
-    retval = response.responseHeader.serviceResult;
     if(retval == UA_STATUSCODE_GOOD) {
         /* Response.securityToken.revisedLifetime is UInt32 we need to cast it
          * to DateTime=Int64 we take 75% of lifetime to start renewing as
          *  described in standard */
-        client->scRenewAt = UA_DateTime_now() +
+        client->nextChannelRenewal = UA_DateTime_nowMonotonic() +
             (UA_DateTime)(response.securityToken.revisedLifetime * (UA_Double)UA_MSEC_TO_DATETIME * 0.75);
 
         /* Replace the old nonce */
-        UA_ChannelSecurityToken_deleteMembers(&client->channel->securityToken);
-        UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel->securityToken);
-        UA_ByteString_deleteMembers(&client->channel->serverNonce);
-        UA_ByteString_copy(&response.serverNonce, &client->channel->serverNonce);
+        UA_ChannelSecurityToken_deleteMembers(&client->channel.securityToken);
+        UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel.securityToken);
+        UA_ByteString_deleteMembers(&client->channel.serverNonce);
+        UA_ByteString_copy(&response.serverNonce, &client->channel.serverNonce);
 
-        if(renew) {
+        if(renew)
             UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                          "SecureChannel renewed");
-        } else {
+        else
             UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                          "SecureChannel opened");
-        }
     } else {
-        UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
-                     "SecureChannel could not be opened / "
-                     "renewed with statuscode %i", retval);
+        if(renew)
+            UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
+                        "SecureChannel could not be renewed "
+                        "with error code %s", UA_StatusCode_name(retval));
+        else
+            UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
+                        "SecureChannel could not be opened "
+                        "with error code %s", UA_StatusCode_name(retval));
     }
+
+    /* Clean up */
     UA_OpenSecureChannelResponse_deleteMembers(&response);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
     return retval;
@@ -507,7 +468,7 @@ static UA_StatusCode SessionHandshake(UA_Client *client) {
 
     request.requestHeader.timestamp = UA_DateTime_now();
     request.requestHeader.timeoutHint = 10000;
-    UA_ByteString_copy(&client->channel->clientNonce, &request.clientNonce);
+    UA_ByteString_copy(&client->channel.clientNonce, &request.clientNonce);
     request.requestedSessionTimeout = 1200000;
     request.maxResponseMessageSize = UA_INT32_MAX;
     UA_String_copy(&client->endpointUrl, &request.endpointUrl);
@@ -543,7 +504,7 @@ static UA_StatusCode CloseSession(UA_Client *client) {
 }
 
 static UA_StatusCode CloseSecureChannel(UA_Client *client) {
-    UA_SecureChannel *channel = client->channel;
+    UA_SecureChannel *channel = &client->channel;
     UA_CloseSecureChannelRequest request;
     UA_CloseSecureChannelRequest_init(&request);
     request.requestHeader.requestHandle = ++client->requestHandle;
@@ -554,7 +515,7 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
 
     UA_SecureConversationMessageHeader msgHeader;
     msgHeader.messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_CLO + UA_CHUNKTYPE_FINAL;
-    msgHeader.secureChannelId = client->channel->securityToken.channelId;
+    msgHeader.secureChannelId = channel->securityToken.channelId;
 
     UA_SymmetricAlgorithmSecurityHeader symHeader;
     symHeader.tokenId = channel->securityToken.tokenId;
@@ -567,8 +528,8 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
         UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST].binaryEncodingId);
 
     UA_ByteString message;
-    UA_Connection *c = client->connection;
-    UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message);
+    UA_Connection *conn = &client->connection;
+    UA_StatusCode retval = conn->getSendBuffer(conn, conn->remoteConf.recvBufferSize, &message);
     if(retval != UA_STATUSCODE_GOOD){
         UA_CloseSecureChannelRequest_deleteMembers(&request);
         return retval;
@@ -587,11 +548,11 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
 
     if(retval == UA_STATUSCODE_GOOD) {
         message.length = msgHeader.messageHeader.messageSize;
-        retval = client->connection->send(client->connection, &message);
+        retval = conn->send(conn, &message);
     } else {
-        client->connection->releaseSendBuffer(client->connection, &message);
+        conn->releaseSendBuffer(conn, &message);
     }
-    client->connection->close(client->connection);
+    conn->close(conn);
     UA_CloseSecureChannelRequest_deleteMembers(&request);
     return retval;
 }
@@ -607,10 +568,10 @@ UA_Client_getEndpoints(UA_Client *client, const char *serverUrl,
 
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    *client->connection =
+    client->connection =
         client->config.connectionFunc(UA_ConnectionConfig_standard, serverUrl,
                                       client->config.logger);
-    if(client->connection->state != UA_CONNECTION_OPENING) {
+    if(client->connection.state != UA_CONNECTION_OPENING) {
         retval = UA_STATUSCODE_BADCONNECTIONCLOSED;
         goto cleanup;
     }
@@ -621,7 +582,7 @@ UA_Client_getEndpoints(UA_Client *client, const char *serverUrl,
         goto cleanup;
     }
 
-    client->connection->localConf = client->config.localConnectionConfig;
+    client->connection.localConf = client->config.localConnectionConfig;
     retval = HelAckHandshake(client);
     if(retval == UA_STATUSCODE_GOOD)
         retval = SecureChannelHandshake(client, false);
@@ -654,10 +615,10 @@ UA_Client_connect(UA_Client *client, const char *endpointUrl) {
     }
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    *client->connection =
+    client->connection =
         client->config.connectionFunc(UA_ConnectionConfig_standard,
                                       endpointUrl, client->config.logger);
-    if(client->connection->state != UA_CONNECTION_OPENING) {
+    if(client->connection.state != UA_CONNECTION_OPENING) {
         retval = UA_STATUSCODE_BADCONNECTIONCLOSED;
         goto cleanup;
     }
@@ -668,7 +629,7 @@ UA_Client_connect(UA_Client *client, const char *endpointUrl) {
         goto cleanup;
     }
 
-    client->connection->localConf = client->config.localConnectionConfig;
+    client->connection.localConf = client->config.localConnectionConfig;
     retval = HelAckHandshake(client);
     if(retval == UA_STATUSCODE_GOOD)
         retval = SecureChannelHandshake(client, false);
@@ -679,7 +640,7 @@ UA_Client_connect(UA_Client *client, const char *endpointUrl) {
     if(retval == UA_STATUSCODE_GOOD)
         retval = ActivateSession(client);
     if(retval == UA_STATUSCODE_GOOD) {
-        client->connection->state = UA_CONNECTION_ESTABLISHED;
+        client->connection.state = UA_CONNECTION_ESTABLISHED;
         client->state = UA_CLIENTSTATE_CONNECTED;
     } else {
         goto cleanup;
@@ -692,15 +653,15 @@ UA_Client_connect(UA_Client *client, const char *endpointUrl) {
 }
 
 UA_StatusCode UA_Client_disconnect(UA_Client *client) {
-    if(client->state != UA_CLIENTSTATE_CONNECTED)
+    if(client->state == UA_CLIENTSTATE_READY)
         return UA_STATUSCODE_BADNOTCONNECTED;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     /* Is a session established? */
-    if(client->connection->state == UA_CONNECTION_ESTABLISHED &&
+    if(client->connection.state == UA_CONNECTION_ESTABLISHED &&
        !UA_NodeId_equal(&client->authenticationToken, &UA_NODEID_NULL))
         retval = CloseSession(client);
     /* Is a secure channel established? */
-    if(client->connection->state == UA_CONNECTION_ESTABLISHED)
+    if(client->connection.state == UA_CONNECTION_ESTABLISHED)
         retval |= CloseSecureChannel(client);
     return retval;
 }
@@ -812,10 +773,10 @@ __UA_Client_Service(UA_Client *client, const void *request, const UA_DataType *r
         return;
     }
 
-    /* Handling request parameters */
-    //here const *request is 'violated'
+    /* Adjusting the request header. The const attribute is violated, but we
+     * only touch the following members: */
     UA_RequestHeader *rr = (UA_RequestHeader*)(uintptr_t)request;
-    UA_NodeId_copy(&client->authenticationToken, &rr->authenticationToken);
+    rr->authenticationToken = client->authenticationToken; /* cleaned up at the end */
     rr->timestamp = UA_DateTime_now();
     rr->requestHandle = ++client->requestHandle;
 
@@ -823,14 +784,14 @@ __UA_Client_Service(UA_Client *client, const void *request, const UA_DataType *r
     UA_UInt32 requestId = ++client->requestId;
     UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
                  "Sending a request of type %i", requestType->typeId.identifier.numeric);
-    retval = UA_SecureChannel_sendBinaryMessage(client->channel, requestId, rr, requestType);
+    retval = UA_SecureChannel_sendBinaryMessage(&client->channel, requestId, rr, requestType);
     if(retval != UA_STATUSCODE_GOOD) {
         if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED)
             respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE;
         else
             respHeader->serviceResult = retval;
-        client->state = UA_CLIENTSTATE_ERRORED;
-        UA_NodeId_deleteMembers(&rr->authenticationToken);
+        client->state = UA_CLIENTSTATE_FAULTED;
+        UA_NodeId_init(&rr->authenticationToken);
         return;
     }
 
@@ -847,7 +808,7 @@ __UA_Client_Service(UA_Client *client, const void *request, const UA_DataType *r
         UA_DateTime now = UA_DateTime_nowMonotonic();
         if(now < maxDate) {
             UA_UInt32 timeout = (UA_UInt32)((maxDate - now) / UA_MSEC_TO_DATETIME);
-            retval = Connection_receiveChunk(client->connection, &reply, &realloced, timeout);
+            retval = UA_Connection_receiveChunksBlocking(&client->connection, &reply, &realloced, timeout);
         } else {
             retval = UA_STATUSCODE_GOODNONCRITICALTIMEOUT;
         }
@@ -856,13 +817,15 @@ __UA_Client_Service(UA_Client *client, const void *request, const UA_DataType *r
             break;
         }
         /* ProcessChunks and call processServiceResponse for complete messages */
-        UA_SecureChannel_processChunks(client->channel, &reply,
+        UA_SecureChannel_processChunks(&client->channel, &reply,
                      (UA_ProcessMessageCallback*)processServiceResponse, &rd);
         /* Free the received buffer */
         if(!realloced)
-            client->connection->releaseRecvBuffer(client->connection, &reply);
+            client->connection.releaseRecvBuffer(&client->connection, &reply);
         else
             UA_ByteString_deleteMembers(&reply);
     } while(!rd.processed);
-    UA_NodeId_deleteMembers(&rr->authenticationToken);
+
+    /* Clean up the authentication token */
+    UA_NodeId_init(&rr->authenticationToken);
 }

+ 1 - 3
src/client/ua_client_highlevel.c

@@ -3,11 +3,9 @@
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ua_client.h"
-#include "ua_nodeids.h"
 #include "ua_client_highlevel.h"
-#include "ua_types_encoding_binary.h"
 #include "ua_util.h"
-#include "ua_types.h"
+#include "ua_nodeids.h"
 
 UA_StatusCode
 UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,

+ 37 - 38
src/client/ua_client_highlevel_subscriptions.c

@@ -5,7 +5,6 @@
 #include "ua_client_highlevel.h"
 #include "ua_client_internal.h"
 #include "ua_util.h"
-#include "ua_types_generated_encoding_binary.h"
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */
 
@@ -34,17 +33,17 @@ UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
 
-    LIST_INIT(&newSub->MonitoredItems);
-    newSub->LifeTime = response.revisedLifetimeCount;
-    newSub->KeepAliveCount = response.revisedMaxKeepAliveCount;
-    newSub->PublishingInterval = response.revisedPublishingInterval;
-    newSub->SubscriptionID = response.subscriptionId;
-    newSub->NotificationsPerPublish = request.maxNotificationsPerPublish;
-    newSub->Priority = request.priority;
+    LIST_INIT(&newSub->monitoredItems);
+    newSub->lifeTime = response.revisedLifetimeCount;
+    newSub->keepAliveCount = response.revisedMaxKeepAliveCount;
+    newSub->publishingInterval = response.revisedPublishingInterval;
+    newSub->subscriptionID = response.subscriptionId;
+    newSub->notificationsPerPublish = request.maxNotificationsPerPublish;
+    newSub->priority = request.priority;
     LIST_INSERT_HEAD(&client->subscriptions, newSub, listEntry);
 
     if(newSubscriptionId)
-        *newSubscriptionId = newSub->SubscriptionID;
+        *newSubscriptionId = newSub->subscriptionID;
 
     UA_CreateSubscriptionResponse_deleteMembers(&response);
     return UA_STATUSCODE_GOOD;
@@ -55,7 +54,7 @@ UA_StatusCode
 UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId) {
     UA_Client_Subscription *sub;
     LIST_FOREACH(sub, &client->subscriptions, listEntry) {
-        if(sub->SubscriptionID == subscriptionId)
+        if(sub->subscriptionID == subscriptionId)
             break;
     }
     if(!sub)
@@ -63,10 +62,10 @@ UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId) {
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Client_MonitoredItem *mon, *tmpmon;
-    LIST_FOREACH_SAFE(mon, &sub->MonitoredItems, listEntry, tmpmon) {
+    LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, tmpmon) {
         retval =
-            UA_Client_Subscriptions_removeMonitoredItem(client, sub->SubscriptionID,
-                                                        mon->MonitoredItemId);
+            UA_Client_Subscriptions_removeMonitoredItem(client, sub->subscriptionID,
+                                                        mon->monitoredItemId);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
     }
@@ -75,7 +74,7 @@ UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId) {
     UA_DeleteSubscriptionsRequest request;
     UA_DeleteSubscriptionsRequest_init(&request);
     request.subscriptionIdsSize = 1;
-    request.subscriptionIds = &sub->SubscriptionID;
+    request.subscriptionIds = &sub->subscriptionID;
     UA_DeleteSubscriptionsResponse response = UA_Client_Service_deleteSubscriptions(client, request);
     retval = response.responseHeader.serviceResult;
     if(retval == UA_STATUSCODE_GOOD && response.resultsSize > 0)
@@ -85,7 +84,7 @@ UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId) {
     if(retval != UA_STATUSCODE_GOOD && retval != UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID) {
         UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_CLIENT,
                     "Could not remove subscription %u with statuscode 0x%08x",
-                    sub->SubscriptionID, retval);
+                    sub->subscriptionID, retval);
         return retval;
     }
 
@@ -97,7 +96,7 @@ void
 UA_Client_Subscriptions_forceDelete(UA_Client *client,
                                     UA_Client_Subscription *sub) {
     UA_Client_MonitoredItem *mon, *mon_tmp;
-    LIST_FOREACH_SAFE(mon, &sub->MonitoredItems, listEntry, mon_tmp) {
+    LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, mon_tmp) {
         UA_NodeId_deleteMembers(&mon->monitoredNodeId);
         LIST_REMOVE(mon, listEntry);
         UA_free(mon);
@@ -113,7 +112,7 @@ UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscripti
                                          void *hfContext, UA_UInt32 *newMonitoredItemId) {
     UA_Client_Subscription *sub;
     LIST_FOREACH(sub, &client->subscriptions, listEntry) {
-        if(sub->SubscriptionID == subscriptionId)
+        if(sub->subscriptionID == subscriptionId)
             break;
     }
     if(!sub)
@@ -129,7 +128,7 @@ UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscripti
     item.itemToMonitor.attributeId = attributeID;
     item.monitoringMode = UA_MONITORINGMODE_REPORTING;
     item.requestedParameters.clientHandle = ++(client->monitoredItemHandles);
-    item.requestedParameters.samplingInterval = sub->PublishingInterval;
+    item.requestedParameters.samplingInterval = sub->publishingInterval;
     item.requestedParameters.discardOldest = true;
     item.requestedParameters.queueSize = 1;
     request.itemsToCreate = &item;
@@ -149,18 +148,18 @@ UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscripti
 
     /* Create the handler */
     UA_Client_MonitoredItem *newMon = (UA_Client_MonitoredItem *)UA_malloc(sizeof(UA_Client_MonitoredItem));
-    newMon->MonitoringMode = UA_MONITORINGMODE_REPORTING;
+    newMon->monitoringMode = UA_MONITORINGMODE_REPORTING;
     UA_NodeId_copy(&nodeId, &newMon->monitoredNodeId);
-    newMon->AttributeID = attributeID;
-    newMon->ClientHandle = client->monitoredItemHandles;
-    newMon->SamplingInterval = sub->PublishingInterval;
-    newMon->QueueSize = 1;
-    newMon->DiscardOldest = true;
+    newMon->attributeID = attributeID;
+    newMon->clientHandle = client->monitoredItemHandles;
+    newMon->samplingInterval = sub->publishingInterval;
+    newMon->queueSize = 1;
+    newMon->discardOldest = true;
     newMon->handler = hf;
     newMon->handlerContext = hfContext;
-    newMon->MonitoredItemId = response.results[0].monitoredItemId;
-    LIST_INSERT_HEAD(&sub->MonitoredItems, newMon, listEntry);
-    *newMonitoredItemId = newMon->MonitoredItemId;
+    newMon->monitoredItemId = response.results[0].monitoredItemId;
+    LIST_INSERT_HEAD(&sub->monitoredItems, newMon, listEntry);
+    *newMonitoredItemId = newMon->monitoredItemId;
 
     UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
                  "Created a monitored item with client handle %u", client->monitoredItemHandles);
@@ -174,15 +173,15 @@ UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscri
                                             UA_UInt32 monitoredItemId) {
     UA_Client_Subscription *sub;
     LIST_FOREACH(sub, &client->subscriptions, listEntry) {
-        if(sub->SubscriptionID == subscriptionId)
+        if(sub->subscriptionID == subscriptionId)
             break;
     }
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
     
     UA_Client_MonitoredItem *mon;
-    LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
-        if(mon->MonitoredItemId == monitoredItemId)
+    LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
+        if(mon->monitoredItemId == monitoredItemId)
             break;
     }
     if(!mon)
@@ -191,9 +190,9 @@ UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscri
     /* remove the monitoreditem remotely */
     UA_DeleteMonitoredItemsRequest request;
     UA_DeleteMonitoredItemsRequest_init(&request);
-    request.subscriptionId = sub->SubscriptionID;
+    request.subscriptionId = sub->subscriptionID;
     request.monitoredItemIdsSize = 1;
-    request.monitoredItemIds = &mon->MonitoredItemId;
+    request.monitoredItemIds = &mon->monitoredItemId;
     UA_DeleteMonitoredItemsResponse response = UA_Client_Service_deleteMonitoredItems(client, request);
 
     UA_StatusCode retval = response.responseHeader.serviceResult;
@@ -223,7 +222,7 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
     /* Find the subscription */
     UA_Client_Subscription *sub;
     LIST_FOREACH(sub, &client->subscriptions, listEntry) {
-        if(sub->SubscriptionID == response->subscriptionId)
+        if(sub->subscriptionID == response->subscriptionId)
             break;
     }
     if(!sub)
@@ -268,23 +267,23 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
         for(size_t j = 0; j < dataChangeNotification->monitoredItemsSize; ++j) {
             UA_MonitoredItemNotification *mitemNot = &dataChangeNotification->monitoredItems[j];
             UA_Client_MonitoredItem *mon;
-            LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
-                if(mon->ClientHandle == mitemNot->clientHandle) {
-                    mon->handler(mon->MonitoredItemId, &mitemNot->value, mon->handlerContext);
+            LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
+                if(mon->clientHandle == mitemNot->clientHandle) {
+                    mon->handler(mon->monitoredItemId, &mitemNot->value, mon->handlerContext);
                     break;
                 }
             }
             if(!mon)
                 UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
                              "Could not process a notification with clienthandle %u on subscription %u",
-                             mitemNot->clientHandle, sub->SubscriptionID);
+                             mitemNot->clientHandle, sub->subscriptionID);
         }
     }
 
     /* Add to the list of pending acks */
     UA_Client_NotificationsAckNumber *tmpAck = (UA_Client_NotificationsAckNumber *)UA_malloc(sizeof(UA_Client_NotificationsAckNumber));
     tmpAck->subAck.sequenceNumber = msg->sequenceNumber;
-    tmpAck->subAck.subscriptionId = sub->SubscriptionID;
+    tmpAck->subAck.subscriptionId = sub->subscriptionID;
     LIST_INSERT_HEAD(&client->pendingNotificationsAcks, tmpAck, listEntry);
 }
 

+ 30 - 30
src/client/ua_client_internal.h

@@ -14,37 +14,38 @@
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 
-typedef struct UA_Client_NotificationsAckNumber_s {
-    LIST_ENTRY(UA_Client_NotificationsAckNumber_s) listEntry;
+typedef struct UA_Client_NotificationsAckNumber {
+    LIST_ENTRY(UA_Client_NotificationsAckNumber) listEntry;
     UA_SubscriptionAcknowledgement subAck;
 } UA_Client_NotificationsAckNumber;
 
-typedef struct UA_Client_MonitoredItem_s {
-    LIST_ENTRY(UA_Client_MonitoredItem_s)  listEntry;
-    UA_UInt32 MonitoredItemId;
-    UA_UInt32 MonitoringMode;
+typedef struct UA_Client_MonitoredItem {
+    LIST_ENTRY(UA_Client_MonitoredItem)  listEntry;
+    UA_UInt32 monitoredItemId;
+    UA_UInt32 monitoringMode;
     UA_NodeId monitoredNodeId;
-    UA_UInt32 AttributeID;
-    UA_UInt32 ClientHandle;
-    UA_Double SamplingInterval;
-    UA_UInt32 QueueSize;
-    UA_Boolean DiscardOldest;
+    UA_UInt32 attributeID;
+    UA_UInt32 clientHandle;
+    UA_Double samplingInterval;
+    UA_UInt32 queueSize;
+    UA_Boolean discardOldest;
     void (*handler)(UA_UInt32 monId, UA_DataValue *value, void *context);
     void *handlerContext;
 } UA_Client_MonitoredItem;
 
-typedef struct UA_Client_Subscription_s {
-    LIST_ENTRY(UA_Client_Subscription_s) listEntry;
-    UA_UInt32 LifeTime;
-    UA_UInt32 KeepAliveCount;
-    UA_Double PublishingInterval;
-    UA_UInt32 SubscriptionID;
-    UA_UInt32 NotificationsPerPublish;
-    UA_UInt32 Priority;
-    LIST_HEAD(UA_ListOfClientMonitoredItems, UA_Client_MonitoredItem_s) MonitoredItems;
+typedef struct UA_Client_Subscription {
+    LIST_ENTRY(UA_Client_Subscription) listEntry;
+    UA_UInt32 lifeTime;
+    UA_UInt32 keepAliveCount;
+    UA_Double publishingInterval;
+    UA_UInt32 subscriptionID;
+    UA_UInt32 notificationsPerPublish;
+    UA_UInt32 priority;
+    LIST_HEAD(UA_ListOfClientMonitoredItems, UA_Client_MonitoredItem) monitoredItems;
 } UA_Client_Subscription;
 
 void UA_Client_Subscriptions_forceDelete(UA_Client *client, UA_Client_Subscription *sub);
+
 #endif
 
 /**********/
@@ -59,12 +60,16 @@ typedef enum {
 struct UA_Client {
     /* State */
     UA_ClientState state;
+    UA_ClientConfig config;
 
     /* Connection */
-    UA_Connection *connection;
-    UA_SecureChannel *channel;
+    UA_Connection connection;
     UA_String endpointUrl;
+
+    /* SecureChannel */
+    UA_SecureChannel channel;
     UA_UInt32 requestId;
+    UA_DateTime nextChannelRenewal;
 
     /* Authentication */
     UA_Client_Authentication authenticationMethod;
@@ -76,17 +81,12 @@ struct UA_Client {
     UA_NodeId authenticationToken;
     UA_UInt32 requestHandle;
     
+    /* Subscriptions */
 #ifdef UA_ENABLE_SUBSCRIPTIONS
     UA_UInt32 monitoredItemHandles;
-    LIST_HEAD(UA_ListOfUnacknowledgedNotificationNumbers, UA_Client_NotificationsAckNumber_s) pendingNotificationsAcks;
-    LIST_HEAD(UA_ListOfClientSubscriptionItems, UA_Client_Subscription_s) subscriptions;
+    LIST_HEAD(ListOfUnacknowledgedNotifications, UA_Client_NotificationsAckNumber) pendingNotificationsAcks;
+    LIST_HEAD(ListOfClientSubscriptionItems, UA_Client_Subscription) subscriptions;
 #endif
-    
-    /* Config */
-    UA_ClientConfig config;
-    UA_DateTime scRenewAt;
 };
 
-
-
 #endif /* UA_CLIENT_INTERNAL_H_ */

+ 9 - 6
src/server/ua_server_binary.c

@@ -379,7 +379,8 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
                                 "Client requested a subscription, " \
                                 "but those are not enabled in the build");
         } else {
-            UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Unknown request %i",
+            UA_LOG_INFO_CHANNEL(server->config.logger, channel,
+                                "Unknown request with type identifier %i",
                                 requestTypeId.identifier.numeric);
         }
         sendError(channel, msg, requestPos, &UA_TYPES[UA_TYPES_SERVICEFAULT],
@@ -400,7 +401,8 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
                              server->config.customDataTypesSize,
                              server->config.customDataTypes);
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Could not decode the request");
+        UA_LOG_DEBUG_CHANNEL(server->config.logger, channel,
+                             "Could not decode the request");
         sendError(channel, msg, requestPos, responseType, requestId, retval);
         return;
     }
@@ -505,8 +507,9 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
     retval = UA_SecureChannel_sendBinaryMessage(channel, requestId, response, responseType);
 
     if(retval != UA_STATUSCODE_GOOD)
-        UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Could not send the message over "
-                             "the SecureChannel with error code 0x%08x", retval);
+        UA_LOG_INFO_CHANNEL(server->config.logger, channel,
+                            "Could not send the message over the SecureChannel "
+                            "with StatusCode %s", UA_StatusCode_name(retval));
 
     /* Clean up */
     UA_deleteMembers(request, requestType);
@@ -557,8 +560,8 @@ UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection,
             UA_SecureChannel_processChunks(channel, message,
                  (UA_ProcessMessageCallback*)UA_Server_processSecureChannelMessage, server);
         if(retval != UA_STATUSCODE_GOOD)
-            UA_LOG_TRACE_CHANNEL(server->config.logger, channel,
-                                 "Procesing chunkgs resulted in error code 0x%08x", retval);
+            UA_LOG_TRACE_CHANNEL(server->config.logger, channel, "Procesing chunks "
+                                 "resulted in error code %s", UA_StatusCode_name(retval));
     } else {
         /* Process messages without a channel and no chunking */
         size_t offset = 0;

+ 28 - 0
src/ua_connection.c

@@ -152,6 +152,34 @@ UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RES
     return UA_STATUSCODE_GOOD;
 }
 
+UA_StatusCode
+UA_Connection_receiveChunksBlocking(UA_Connection *connection, UA_ByteString *chunks,
+                                    UA_Boolean *realloced, UA_UInt32 timeout) {
+    UA_DateTime now = UA_DateTime_nowMonotonic();
+    UA_DateTime maxDate = now + (timeout * UA_MSEC_TO_DATETIME);
+    *realloced = false;
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    while(true) {
+        /* Listen for messages to arrive */
+        retval = connection->recv(connection, chunks, timeout);
+
+        /* Get complete chunks and return */
+        retval |= UA_Connection_completeMessages(connection, chunks, realloced);
+        if(retval != UA_STATUSCODE_GOOD || chunks->length > 0)
+            break;
+
+        /* We received a message. But the chunk is incomplete. Compute the
+         * remaining timeout. */
+        now = UA_DateTime_nowMonotonic();
+        if(now > maxDate)
+            return UA_STATUSCODE_GOODNONCRITICALTIMEOUT;
+        timeout = (UA_UInt32)((maxDate - now) / UA_MSEC_TO_DATETIME);
+    }
+    return retval;
+}
+
+
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {
     UA_SecureChannel *channel = connection->channel;
     if(channel)

+ 35 - 18
src/ua_connection_internal.h

@@ -11,8 +11,7 @@ extern "C" {
 
 #include "ua_connection.h"
 
-/**
- * The network layer may receive chopped up messages since TCP is a streaming
+/* The network layer may receive chopped up messages since TCP is a streaming
  * protocol. Furthermore, the networklayer may operate on ringbuffers or
  * statically assigned memory.
  *
@@ -27,28 +26,46 @@ extern "C" {
  * @param realloced The Boolean value is set to true if the outgoing message has
  *        been reallocated from the network layer.
  * @return Returns UA_STATUSCODE_GOOD or an error code. When an error occurs, the ingoing message
- *         and the current buffer in the connection are freed.
- */
+ *         and the current buffer in the connection are freed. */
 UA_StatusCode
-UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
-                               UA_Boolean * UA_RESTRICT realloced);
-
-void UA_EXPORT UA_Connection_detachSecureChannel(UA_Connection *connection);
-void UA_EXPORT UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel);
+UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString *message,
+                               UA_Boolean *realloced);
 
-/**
- * EndpointURL helper
+/* Try to receive at least one complete chunk on the connection. This blocks the
+ * current thread up to the given timeout.
+ *
+ * @param connection The connection
+ * @param chunk The received chunk. The memory is allocated either by the
+ *        networklayer or internally.
+ * @param realloced The Boolean value is set to true if the chunk has been
+ *        reallocated from the network layer.
+ * @param timeout The timeout (in milliseconds) the method will block at most.
+ * @return Returns UA_STATUSCODE_GOOD or an error code. When an error occurs,
+ *         the chunk buffer is returned empty. Upon a timeout,
+ *         UA_STATUSCODE_GOODNONCRITICALTIMEOUT is returned.
  */
+UA_StatusCode
+UA_Connection_receiveChunksBlocking(UA_Connection *connection, UA_ByteString *chunks,
+                                    UA_Boolean *realloced, UA_UInt32 timeout);
+
+void UA_Connection_detachSecureChannel(UA_Connection *connection);
+void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel);
 
-/**
- * Split the given endpoint url into hostname and port. Some of the chunks are returned as pointer.
+/* Split the given endpoint url into hostname and port. Some of the chunks are
+ * returned as pointer.
  * @param endpointUrl The endpoint URL to split up
  * @param hostname the target array for hostname. Has to be at least 256 size.
- * @param port if url contains port, it will point to the beginning of port. NULL otherwise. It may also include the path part, thus stop at position of path pointer, if it is not NULL.
- * @param path points to the first occurance of '/' after the port or NULL if no path in url
- * @return UA_STATUSCODE_BADOUTOFRANGE if url too long, UA_STATUSCODE_BADATTRIBUTEIDINVALID if url not starting with 'opc.tcp://', UA_STATUSCODE_GOOD on success
- */
-UA_StatusCode UA_EXPORT UA_EndpointUrl_split_ptr(const char *endpointUrl, char *hostname, const char ** port, const char ** path);
+ * @param port if url contains port, it will point to the beginning of port.
+ *        NULL otherwise. It may also include the path part, thus stop at
+ *        position of path pointer, if it is not NULL.
+ * @param path points to the first occurance of '/' after the port or NULL if no
+ *        path in url
+ * @return UA_STATUSCODE_BADOUTOFRANGE if url too long,
+ *         UA_STATUSCODE_BADATTRIBUTEIDINVALID if url not starting with
+ *         'opc.tcp://', UA_STATUSCODE_GOOD on success */
+UA_StatusCode
+UA_EndpointUrl_split_ptr(const char *endpointUrl, char *hostname,
+                         const char ** port, const char ** path);
 
 #ifdef __cplusplus
 } // extern "C"

+ 3 - 2
src/ua_securechannel.c

@@ -15,8 +15,9 @@
 
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
     memset(channel, 0, sizeof(UA_SecureChannel));
-    LIST_INIT(&channel->sessions);
-    LIST_INIT(&channel->chunks);
+    /* Linked lists are also initialized by zeroing out */
+    /* LIST_INIT(&channel->sessions); */
+    /* LIST_INIT(&channel->chunks); */
 }
 
 void UA_SecureChannel_deleteMembersCleanup(UA_SecureChannel *channel) {