Kaynağa Gözat

Don't use calcSizeBinary. Return a failure message if the response message would be too large.

Julius Pfrommer 9 yıl önce
ebeveyn
işleme
8413eceba6

+ 9 - 21
examples/networklayer_tcp.c

@@ -62,18 +62,16 @@ static UA_StatusCode socket_write(UA_Connection *connection, UA_ByteString *buf,
 }
 
 static UA_StatusCode socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-	if(response->data == NULL)
-        retval = connection->getBuffer(connection, response, connection->localConf.recvBufferSize);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
+    response->data = malloc(connection->localConf.recvBufferSize);
+    if(!response->data)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
     struct timeval tmptv = {0, timeout * 1000};
     if(0 != setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv, sizeof(struct timeval))){
         return UA_STATUSCODE_BADINTERNALERROR;
     }
-    int ret = recv(connection->sockfd, (char*)response->data, response->length, 0);
+    int ret = recv(connection->sockfd, (char*)response->data, connection->localConf.recvBufferSize, 0);
 	if(ret == 0) {
-		connection->releaseBuffer(connection, response);
+		UA_free(response->data);
 		connection->close(connection);
 		return UA_STATUSCODE_BADCONNECTIONCLOSED;
 	} else if(ret < 0) {
@@ -84,7 +82,7 @@ static UA_StatusCode socket_recv(UA_Connection *connection, UA_ByteString *respo
 #endif
             return UA_STATUSCODE_BADCOMMUNICATIONERROR;
         }
-        connection->releaseBuffer(connection, response);
+		UA_free(response->data);
 		connection->close(connection);
         return UA_STATUSCODE_BADCONNECTIONCLOSED;
     }
@@ -175,10 +173,9 @@ typedef struct {
     } *deletes;
 } ServerNetworkLayerTCP;
 
-static UA_StatusCode ServerNetworkLayerGetBuffer(UA_Connection *connection, UA_ByteString *buf,
-                                                 size_t minSize) {
+static UA_StatusCode ServerNetworkLayerGetBuffer(UA_Connection *connection, UA_ByteString *buf) {
 #ifdef UA_MULTITHREADING
-    return UA_ByteString_newMembers(buf, minSize);
+    return UA_ByteString_newMembers(buf, connection->remoteConf.recvBufferSize);
 #else
     ServerNetworkLayerTCP *layer = connection->handle;
     *buf = layer->buffer;
@@ -398,12 +395,6 @@ static UA_Int32 ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job
     for(size_t i = 0; i < layer->mappingsSize && j < resultsize; i++) {
         if(!(FD_ISSET(layer->mappings[i].sockfd, &layer->fdset)))
             continue;
-        if(!buf.data) {
-            buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
-            buf.length = layer->conf.recvBufferSize;
-            if(!buf.data)
-                break;
-        }
         if(socket_recv(layer->mappings[i].connection, &buf, 0) == UA_STATUSCODE_GOOD) {
             items[j].type = UA_JOBTYPE_BINARYMESSAGE;
             items[j].job.binaryMessage.message = buf;
@@ -424,9 +415,6 @@ static UA_Int32 ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job
         j++;
     }
 
-    if(buf.data)
-        free(buf.data);
-
     /* free the array if there is no job */
     if(j == 0) {
         free(items);
@@ -513,7 +501,7 @@ UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UIn
 /* Client NetworkLayer TCP */
 /***************************/
 
-static UA_StatusCode ClientNetworkLayerGetBuffer(UA_Connection *connection, UA_ByteString *buf, size_t minSize) {
+static UA_StatusCode ClientNetworkLayerGetBuffer(UA_Connection *connection, UA_ByteString *buf) {
 #ifndef UA_MULTITHREADING
     *buf = *(UA_ByteString*)connection->handle;
     return UA_STATUSCODE_GOOD;

+ 1 - 1
include/ua_connection.h

@@ -64,7 +64,7 @@ struct UA_Connection {
     UA_Int32 sockfd; ///> Most connectivity solutions run on sockets. Having the socket id here simplifies the design.
     void *handle; ///> A pointer to the networklayer
     UA_ByteString incompleteMessage; ///> Half-received messages (tcp is a streaming protocol) get stored here
-    UA_StatusCode (*getBuffer)(UA_Connection *connection, UA_ByteString *buf, size_t minSize); ///> Attach the data array to the buffer. Fails if minSize is larger than remoteConf allows
+    UA_StatusCode (*getBuffer)(UA_Connection *connection, UA_ByteString *buf); ///> Get a buffer of the maximum remote recv size
     void (*releaseBuffer)(UA_Connection *connection, UA_ByteString *buf); ///> Release the buffer manually
     /**
      * Sends a message over the connection.

+ 3 - 5
src/client/ua_client.c

@@ -73,7 +73,7 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
     messageHeader.messageSize = UA_TcpHelloMessage_calcSizeBinary((UA_TcpHelloMessage const*)&hello) +
                                 UA_TcpMessageHeader_calcSizeBinary((UA_TcpMessageHeader const*)&messageHeader);
     UA_ByteString message;
-    UA_StatusCode retval = c->connection.getBuffer(&c->connection, &message, messageHeader.messageSize);
+    UA_StatusCode retval = c->connection.getBuffer(&c->connection, &message);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
@@ -150,8 +150,7 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
         UA_OpenSecureChannelRequest_calcSizeBinary(&opnSecRq);
 
     UA_ByteString message;
-    UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message,
-                                                        messageHeader.messageHeader.messageSize);
+    UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
@@ -436,8 +435,7 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
         UA_calcSizeBinary(&request, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST]);
 
     UA_ByteString message;
-    UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message,
-                                                        msgHeader.messageHeader.messageSize);
+    UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 

+ 24 - 21
src/server/ua_server_binary.c

@@ -40,11 +40,12 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size
 
     UA_TcpMessageHeader ackHeader;
     ackHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_ACKF;
-    ackHeader.messageSize = UA_TcpMessageHeader_calcSizeBinary(&ackHeader) 
-        + UA_TcpAcknowledgeMessage_calcSizeBinary(&ackMessage);
+    ackHeader.messageSize =  8 + 20;
+    /* == UA_TcpMessageHeader_calcSizeBinary(&ackHeader) +
+       UA_TcpAcknowledgeMessage_calcSizeBinary(&ackMessage) */
 
     UA_ByteString ack_msg;
-    if(connection->getBuffer(connection, &ack_msg, ackHeader.messageSize) != UA_STATUSCODE_GOOD)
+    if(connection->getBuffer(connection, &ack_msg) != UA_STATUSCODE_GOOD)
         return;
 
     size_t tmpPos = 0;
@@ -109,33 +110,35 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
                                                UA_ENCODINGOFFSET_BINARY);
 
-    respHeader.messageHeader.messageSize =
-        UA_SecureConversationMessageHeader_calcSizeBinary(&respHeader)
-        + UA_AsymmetricAlgorithmSecurityHeader_calcSizeBinary(&asymHeader)
-        + UA_SequenceHeader_calcSizeBinary(&seqHeader)
-        + UA_NodeId_calcSizeBinary(&responseType)
-        + UA_OpenSecureChannelResponse_calcSizeBinary(&p);
-
     UA_ByteString resp_msg;
-    retval = connection->getBuffer(connection, &resp_msg, respHeader.messageHeader.messageSize);
+    retval = connection->getBuffer(connection, &resp_msg);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_OpenSecureChannelResponse_deleteMembers(&p);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         return;
     }
         
-    size_t tmpPos = 0;
-    UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
-    UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back
-    UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos); // just mirror back
-    UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos);
-    UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos);
-    UA_OpenSecureChannelResponse_deleteMembers(&p);
-    UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
+    size_t tmpPos = 12; /* skip the secureconversationmessageheader for now */
+    retval |= UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back
+    retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos); // just mirror back
+    retval |= UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos);
+    retval |= UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos);
 
-    if(connection->write(connection, &resp_msg,
-                         respHeader.messageHeader.messageSize) != UA_STATUSCODE_GOOD)
+    if(retval != UA_STATUSCODE_GOOD) {
         connection->releaseBuffer(connection, &resp_msg);
+        connection->close(connection);
+    } else {
+        respHeader.messageHeader.messageSize = tmpPos;
+        tmpPos = 0;
+        UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
+
+        if(connection->write(connection, &resp_msg,
+                             respHeader.messageHeader.messageSize) != UA_STATUSCODE_GOOD)
+            connection->releaseBuffer(connection, &resp_msg);
+    }
+
+    UA_OpenSecureChannelResponse_deleteMembers(&p);
+    UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
 }
 
 static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r) {

+ 2 - 2
src/ua_connection.c

@@ -10,8 +10,8 @@ const UA_ConnectionConfig UA_ConnectionConfig_standard =
 
 void UA_Connection_init(UA_Connection *connection) {
     connection->state = UA_CONNECTION_CLOSED;
-    connection->localConf = (UA_ConnectionConfig){0,0,0,0,0};
-    connection->remoteConf = (UA_ConnectionConfig){0,0,0,0,0};
+    connection->localConf = UA_ConnectionConfig_standard;
+    connection->remoteConf = UA_ConnectionConfig_standard;
     connection->channel = UA_NULL;
     connection->sockfd = 0;
     connection->handle = UA_NULL;

+ 21 - 13
src/ua_securechannel.c

@@ -111,31 +111,39 @@ UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_U
     UA_SequenceHeader seqHeader;
     seqHeader.requestId = requestId;
 
-    respHeader.messageHeader.messageSize =
-        UA_SecureConversationMessageHeader_calcSizeBinary(&respHeader)
-        + UA_SymmetricAlgorithmSecurityHeader_calcSizeBinary(&symSecHeader)
-        + UA_SequenceHeader_calcSizeBinary(&seqHeader)
-        + UA_NodeId_calcSizeBinary(&typeId)
-        + UA_calcSizeBinary(content, contentType);
-
     UA_ByteString message;
-    UA_StatusCode retval = connection->getBuffer(connection, &message, respHeader.messageHeader.messageSize);
-    if(retval)
+    UA_StatusCode retval = connection->getBuffer(connection, &message);
+    if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
-    /* do this only now, so the sequence number does not increase if sth fails */
+    size_t messagePos = 24; // after the headers
+    retval |= UA_NodeId_encodeBinary(&typeId, &message, &messagePos);
+    retval |= UA_encodeBinary(content, contentType, &message, &messagePos);
+
+    /* write a failure message if necessary */
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_ServiceFault r;
+        UA_ServiceFault_init(&r);
+        r.responseHeader = *(const UA_ResponseHeader*)content;
+        r.responseHeader.serviceResult = retval;
+        size_t messagePos = 24;
+        UA_NodeId_encodeBinary(&UA_TYPES[UA_TYPES_SERVICEFAULT].typeId, &message, &messagePos);
+        UA_encodeBinary(&r, &UA_TYPES[UA_TYPES_SERVICEFAULT], &message, &messagePos);
+        UA_ServiceFault_init(&r);
+    }
+
+    /* now write the header with the size */
+    respHeader.messageHeader.messageSize = messagePos;
 #ifndef UA_MULTITHREADING
     seqHeader.sequenceNumber = ++channel->sequenceNumber;
 #else
     seqHeader.sequenceNumber = uatomic_add_return(&channel->sequenceNumber, 1);
 #endif
 
-    size_t messagePos = 0;
+    messagePos = 0;
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &message, &messagePos);
     UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, &message, &messagePos);
     UA_SequenceHeader_encodeBinary(&seqHeader, &message, &messagePos);
-    UA_NodeId_encodeBinary(&typeId, &message, &messagePos);
-    UA_encodeBinary(content, contentType, &message, &messagePos);
     
     if(connection->write(connection, &message, respHeader.messageHeader.messageSize) != UA_STATUSCODE_GOOD)
         connection->releaseBuffer(connection, &message);