Forráskód Böngészése

fix/simplify renewing of securechannels in the client

securechannel renewal has to wait for the response. Process only MSG
responses async in the background
Julius Pfrommer 7 éve
szülő
commit
a792a459b0
3 módosított fájl, 42 hozzáadás és 73 törlés
  1. 1 1
      src/client/ua_client.c
  2. 35 72
      src/client/ua_client_connect.c
  3. 6 0
      src/client/ua_client_internal.h

+ 1 - 1
src/client/ua_client.c

@@ -255,7 +255,7 @@ client_processChunk(void *application, UA_Connection *connection, UA_ByteString
 
 /* Receive and process messages until a synchronous message arrives or the
  * timout finishes */
-static UA_StatusCode
+UA_StatusCode
 receiveServiceResponse(UA_Client *client, void *response, const UA_DataType *responseType,
                        UA_DateTime maxDate, UA_UInt32 *synchronousRequestId) {
     /* Prepare the response and the structure we give into processServiceResponse */

+ 35 - 72
src/client/ua_client_connect.c

@@ -104,65 +104,36 @@ HelAckHandshake(UA_Client *client) {
 }
 
 static UA_StatusCode
-processDecodedOPNResponse(void *application, UA_SecureChannel *channel,
-                          UA_MessageType messageType, UA_UInt32 requestId,
-                          const UA_ByteString *message) {
-    /* Does the request id match? */
-    UA_Client *client = (UA_Client*)application;
-    if(requestId != client->requestId)
-        return UA_STATUSCODE_BADCOMMUNICATIONERROR;
-
-    /* Is the content of the expected type? */
-    size_t offset = 0;
-    UA_NodeId responseId;
-    UA_NodeId expectedId =
-        UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE].binaryEncodingId);
-    UA_StatusCode retval = UA_NodeId_decodeBinary(message, &offset, &responseId);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    if(!UA_NodeId_equal(&responseId, &expectedId)) {
-        UA_NodeId_deleteMembers(&responseId);
-        return UA_STATUSCODE_BADCOMMUNICATIONERROR;
-    }
-    UA_NodeId_deleteMembers(&responseId);
-
-    /* Decode the response */
-    UA_OpenSecureChannelResponse response;
-    retval = UA_OpenSecureChannelResponse_decodeBinary(message, &offset, &response);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-
-    /* 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->nextChannelRenewal = UA_DateTime_nowMonotonic() +
-        (UA_DateTime)(response.securityToken.revisedLifetime * (UA_Double)UA_MSEC_TO_DATETIME * 0.75);
-
+processDecodedOPNResponse(UA_Client *client, const UA_OpenSecureChannelResponse *response) {
     /* Replace the token and nonce */
     UA_ChannelSecurityToken_deleteMembers(&client->channel.securityToken);
     UA_ByteString_deleteMembers(&client->channel.remoteNonce);
-    client->channel.securityToken = response.securityToken;
-    client->channel.remoteNonce = response.serverNonce;
-    UA_ResponseHeader_deleteMembers(&response.responseHeader); /* the other members were moved */
+    UA_StatusCode retval;
+    retval = UA_ChannelSecurityToken_copy(&response->securityToken,
+                                          &client->channel.securityToken);
+    retval |= UA_ByteString_copy(&response->serverNonce, &client->channel.remoteNonce);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
+                       "SecureChannel renewal failed!");
+        return retval;
+    }
+
     if(client->channel.state == UA_SECURECHANNELSTATE_OPEN)
         UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
-                     "SecureChannel renewed");
+                     "SecureChannel in the server renewed");
     else
         UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
-                     "SecureChannel opened");
+                     "Opened SecureChannel acknowledged by the server");
+
+    /* 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->channel.state = UA_SECURECHANNELSTATE_OPEN;
+    client->nextChannelRenewal = UA_DateTime_nowMonotonic() +
+        (UA_DateTime)(response->securityToken.revisedLifetime * (UA_Double)UA_MSEC_TO_DATETIME * 0.75);
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode
-processOPNResponse(void *application, UA_Connection *connection, UA_ByteString *chunk) {
-    UA_Client *client = (UA_Client*)application;
-    return UA_SecureChannel_processChunk(&client->channel, chunk,
-                                         processDecodedOPNResponse,
-                                         client);
-}
-
-/* OPN messges to renew the channel are sent asynchronous */
 static UA_StatusCode
 openSecureChannel(UA_Client *client, UA_Boolean renew) {
     /* Check if sc is still valid */
@@ -191,43 +162,35 @@ openSecureChannel(UA_Client *client, UA_Boolean renew) {
     opnSecRq.clientNonce = client->channel.localNonce;
     opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
 
-    /* Prepare the entry for the linked list */
-    UA_UInt32 requestId = ++client->requestId;
-    AsyncServiceCall *ac = NULL;
-    if(renew) {
-        ac = (AsyncServiceCall*)UA_malloc(sizeof(AsyncServiceCall));
-        if(!ac)
-            return UA_STATUSCODE_BADOUTOFMEMORY;
-        ac->callback = (UA_ClientAsyncServiceCallback)processDecodedOPNResponse;
-        ac->responseType = &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE];
-        ac->requestId = requestId;
-        ac->userdata = NULL;
-    }
-
     /* Send the OPN message */
+    UA_UInt32 requestId = ++client->requestId;
     UA_StatusCode retval =
-        UA_SecureChannel_sendAsymmetricOPNMessage(&client->channel, requestId,
-                                                  &opnSecRq, &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST]);
+        UA_SecureChannel_sendAsymmetricOPNMessage(&client->channel, requestId, &opnSecRq,
+                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST]);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                      "Sending OPN message failed with error %s", UA_StatusCode_name(retval));
         UA_Client_disconnect(client);
-        if(ac)
-            UA_free(ac);
         return retval;
     }
 
     UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "OPN message sent");
 
-    if(!renew) {
-        /* During OpenSecureChannel, block until the response */
-        retval = UA_Connection_receiveChunksBlocking(&client->connection, client,
-                                                     processOPNResponse, client->config.timeout);
-    } else {
-        /* For renewal, store the entry for async processing and return */
-        LIST_INSERT_HEAD(&client->asyncServiceCalls, ac, pointers);
+    /* Receive / decrypt / decode the OPN response. Process async services in
+     * the background until the OPN response arrives. */
+    UA_OpenSecureChannelResponse response;
+    retval = receiveServiceResponse(client, &response,
+                                    &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE],
+                                    UA_DateTime_nowMonotonic() + (UA_DateTime)
+                                    ((UA_Double)client->config.timeout * UA_DATETIME_TO_MSEC),
+                                    &requestId);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Client_disconnect(client);
+        return retval;
     }
 
+    retval = processDecodedOPNResponse(client, &response);
+    UA_OpenSecureChannelResponse_deleteMembers(&response);
     return retval;
 }
 

+ 6 - 0
src/client/ua_client_internal.h

@@ -111,4 +111,10 @@ UA_StatusCode
 UA_Client_getEndpointsInternal(UA_Client *client, size_t* endpointDescriptionsSize,
                                UA_EndpointDescription** endpointDescriptions);
 
+/* Receive and process messages until a synchronous message arrives or the
+ * timout finishes */
+UA_StatusCode
+receiveServiceResponse(UA_Client *client, void *response, const UA_DataType *responseType,
+                       UA_DateTime maxDate, UA_UInt32 *synchronousRequestId);
+
 #endif /* UA_CLIENT_INTERNAL_H_ */