Browse Source

Fix connection close after secure channel renew with background publish

The client currently sets the new security token as soon as it receives
an OpenSecureChannelResponse. If a publish response with the old tokenId
is received after the OpenSecureChannelResponse, the client closes the
connection.

This patch saves the new security token to the nextSecurityToken member
of UA_SecureChannel. If a message with the new tokenId arrives, the old
security token is replaced with the new security token.
If the client is the first to send a message, the token is also replaced.

To support a fully asynchronous client, the secure channel implementation
should be modified to fulfill the requirements in OPC UA part 4, 5.5.2.1.
Jannis Voelker 6 years ago
parent
commit
2dc11f85cd
2 changed files with 9 additions and 5 deletions
  1. 3 0
      src/client/ua_client.c
  2. 6 5
      src/client/ua_client_connect.c

+ 3 - 0
src/client/ua_client.c

@@ -282,6 +282,9 @@ sendSymmetricServiceRequest(UA_Client *client, const void *request,
     UA_UInt32 rqId = ++client->requestId;
     UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
                  "Sending a request of type %i", requestType->typeId.identifier.numeric);
+
+    if (client->channel.nextSecurityToken.tokenId != 0) // Change to the new security token if the secure channel has been renewed.
+        UA_SecureChannel_revolveTokens(&client->channel);
     retval = UA_SecureChannel_sendSymmetricMessage(&client->channel, rqId, UA_MESSAGETYPE_MSG,
                                                    rr, requestType);
     UA_NodeId_init(&rr->authenticationToken); /* Do not return the token to the user */

+ 6 - 5
src/client/ua_client_connect.c

@@ -130,11 +130,12 @@ HelAckHandshake(UA_Client *client) {
 }
 
 static void
-processDecodedOPNResponse(UA_Client *client, UA_OpenSecureChannelResponse *response) {
+processDecodedOPNResponse(UA_Client *client, UA_OpenSecureChannelResponse *response, UA_Boolean renew) {
     /* Replace the token */
-    UA_ChannelSecurityToken_deleteMembers(&client->channel.securityToken);
-    client->channel.securityToken = response->securityToken;
-    UA_ChannelSecurityToken_init(&response->securityToken);
+    if (renew)
+        client->channel.nextSecurityToken = response->securityToken; // Set the next token
+    else
+        client->channel.securityToken = response->securityToken; // Set initial token
 
     /* Replace the nonce */
     UA_ByteString_deleteMembers(&client->channel.remoteNonce);
@@ -220,7 +221,7 @@ openSecureChannel(UA_Client *client, UA_Boolean renew) {
         return retval;
     }
 
-    processDecodedOPNResponse(client, &response);
+    processDecodedOPNResponse(client, &response, renew);
     UA_OpenSecureChannelResponse_deleteMembers(&response);
     return retval;
 }