Sfoglia il codice sorgente

Add parsing of TCP Error Message 'ERR'

See Table 34 and 37, OPC UA Part 6, Section 7.1
Stefan Profanter 7 anni fa
parent
commit
776c27ba8b

+ 11 - 4
src/client/ua_client.c

@@ -688,16 +688,23 @@ static void
 processServiceResponse(struct ResponseDescription *rd, UA_SecureChannel *channel,
                        UA_MessageType messageType, UA_UInt32 requestId,
                        UA_ByteString *message) {
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     const UA_NodeId expectedNodeId =
-        UA_NODEID_NUMERIC(0, rd->responseType->binaryEncodingId);
+            UA_NODEID_NUMERIC(0, rd->responseType->binaryEncodingId);
     const UA_NodeId serviceFaultNodeId =
-        UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_SERVICEFAULT].binaryEncodingId);
+            UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_SERVICEFAULT].binaryEncodingId);
 
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_ResponseHeader *respHeader = (UA_ResponseHeader*)rd->response;
     rd->processed = true;
 
-    if(messageType != UA_MESSAGETYPE_MSG) {
+    if(messageType == UA_MESSAGETYPE_ERR) {
+        UA_TcpErrorMessage *msg = (UA_TcpErrorMessage*)message;
+        UA_LOG_ERROR(rd->client->config.logger, UA_LOGCATEGORY_CLIENT,
+                     "Server replied with an error message: %s %.*s", UA_StatusCode_name(msg->error), msg->reason.length, msg->reason.data);
+        retval = msg->error;
+        goto finish;
+    } else if(messageType != UA_MESSAGETYPE_MSG) {
         UA_LOG_ERROR(rd->client->config.logger, UA_LOGCATEGORY_CLIENT,
                      "Server replied with the wrong message type");
         retval = UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;

+ 25 - 0
src/server/ua_server_binary.c

@@ -502,6 +502,19 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
     UA_deleteMembers(response, responseType);
 }
 
+/* ERR -> Error from the remote connection */
+static void processERR(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg, size_t *offset) {
+    UA_TcpErrorMessage errorMessage;
+    if (UA_TcpErrorMessage_decodeBinary(msg, offset, &errorMessage) != UA_STATUSCODE_GOOD) {
+        connection->close(connection);
+        return;
+    }
+
+    UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_NETWORK,
+                 "Client replied with an error message: %s %.*s",
+                 UA_StatusCode_name(errorMessage.error), errorMessage.reason.length, errorMessage.reason.data);
+}
+
 /* Takes decoded messages starting at the nodeid of the content type. Only OPN
  * messages start at the asymmetricalgorithmsecurityheader and are not
  * decoded. */
@@ -512,6 +525,13 @@ UA_Server_processSecureChannelMessage(UA_Server *server, UA_SecureChannel *chann
     UA_assert(channel);
     UA_assert(channel->connection);
     switch(messagetype) {
+    case UA_MESSAGETYPE_ERR: {
+        const UA_TcpErrorMessage *msg = (const UA_TcpErrorMessage *) message;
+        UA_LOG_ERROR_CHANNEL(server->config.logger, channel,
+                             "Client replied with an error message: %s %.*s",
+                             UA_StatusCode_name(msg->error), msg->reason.length, msg->reason.data);
+        break;
+    }
     case UA_MESSAGETYPE_HEL:
         UA_LOG_TRACE_CHANNEL(server->config.logger, channel,
                              "Cannot process a HEL on an open channel");
@@ -562,6 +582,11 @@ UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection,
 
         /* Dispatch according to the message type */
         switch(tcpMessageHeader.messageTypeAndChunkType & 0x00ffffff) {
+        case UA_MESSAGETYPE_ERR:
+            UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK,
+                         "Connection %i | Process ERR message", connection->sockfd);
+            processERR(server, connection, message, &offset);
+            break;
         case UA_MESSAGETYPE_HEL:
             UA_LOG_TRACE(server->config.logger, UA_LOGCATEGORY_NETWORK,
                          "Connection %i | Process HEL message", connection->sockfd);

+ 1 - 0
src/ua_connection.c

@@ -44,6 +44,7 @@ UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString *message
             ((UA_UInt32)message->data[complete_until+1] << 8) +
             ((UA_UInt32)message->data[complete_until+2] << 16);
         if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
+           msgtype != ('E' + ('R' << 8) + ('R' << 16)) &&
            msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
            msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
            msgtype != ('A' + ('C' << 8) + ('K' << 16)) &&

+ 17 - 0
src/ua_securechannel.c

@@ -361,6 +361,23 @@ UA_SecureChannel_processChunks(UA_SecureChannel *channel, const UA_ByteString *c
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     size_t offset= 0;
     do {
+
+        if (chunks->length > 3 && chunks->data[offset] == 'E' &&
+                chunks->data[offset+1] == 'R' && chunks->data[offset+2] == 'R') {
+            UA_TcpMessageHeader header;
+            retval = UA_TcpMessageHeader_decodeBinary(chunks, &offset, &header);
+            if(retval != UA_STATUSCODE_GOOD)
+                break;
+
+            UA_TcpErrorMessage errorMessage;
+            retval = UA_TcpErrorMessage_decodeBinary(chunks, &offset, &errorMessage);
+            if(retval != UA_STATUSCODE_GOOD)
+                break;
+
+            callback(application, channel, UA_MESSAGETYPE_ERR, 0, (void*)&errorMessage);
+            continue;
+        }
+
         /* Store the initial offset to compute the header length */
         size_t initial_offset = offset;
 

+ 7 - 0
tools/schema/Custom.Opc.Ua.Transport.bsd

@@ -18,6 +18,7 @@
     <opc:EnumeratedValue Name="MSG" Value="0x47534D" />
     <opc:EnumeratedValue Name="OPN" Value="0x4E504F" />
     <opc:EnumeratedValue Name="CLO" Value="0x4F4C43" />
+    <opc:EnumeratedValue Name="ERR" Value="0x525245" />
   </opc:EnumeratedType>
   
   <opc:EnumeratedType Name="ChunkType" LengthInBits="32">
@@ -52,6 +53,12 @@
     <opc:Field Name="MaxMessageSize" TypeName="opc:UInt32" />
 	<opc:Field Name="MaxChunkCount" TypeName="opc:UInt32" />
   </opc:StructuredType>
+
+  <opc:StructuredType Name="TcpErrorMessage">
+    <opc:Documentation>Error Message</opc:Documentation>
+    <opc:Field Name="Error" TypeName="opc:UInt32" />
+    <opc:Field Name="Reason" TypeName="opc:String" />
+  </opc:StructuredType>
   
   <opc:StructuredType Name="SecureConversationMessageHeader">
     <opc:Documentation>Secure Layer Sequence Header</opc:Documentation>

+ 1 - 0
tools/schema/datatypes_transport.txt

@@ -3,6 +3,7 @@ ChunkType
 TcpMessageHeader
 TcpHelloMessage
 TcpAcknowledgeMessage
+TcpErrorMessage
 SecureConversationMessageHeader
 AsymmetricAlgorithmSecurityHeader
 SymmetricAlgorithmSecurityHeader