Selaa lähdekoodia

take message buffers from the connection layer

Julius Pfrommer 10 vuotta sitten
vanhempi
commit
68cf0f8613

+ 13 - 38
examples/networklayer_tcp.c

@@ -38,48 +38,25 @@
 /* Generic Socket Functions */
 /****************************/
 
-static UA_StatusCode socket_write(UA_Connection *connection, UA_ByteStringArray gather_buf) {
-    UA_UInt32 total_len = 0, nWritten = 0;
-#ifdef _WIN32
-    LPWSABUF buf = _alloca(gather_buf.stringsSize * sizeof(WSABUF));
-    memset(buf, 0, sizeof(gather_buf.stringsSize * sizeof(WSABUF)));
-    for(UA_UInt32 i = 0; i<gather_buf.stringsSize; i++) {
-        buf[i].buf = (char*)gather_buf.strings[i].data;
-        buf[i].len = gather_buf.strings[i].length;
-        total_len += gather_buf.strings[i].length;
-    }
-    int result = 0;
-    while(nWritten < total_len) {
-        UA_UInt32 n = 0;
+static UA_StatusCode socket_write(UA_Connection *connection, const UA_ByteString *buf) {
+    if(buf->length < 0)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    UA_Int32 nWritten = 0;
+    while (nWritten < buf->length) {
+        UA_Int32 n = 0;
         do {
-            result = WSASend(connection->sockfd, buf, gather_buf.stringsSize, (LPDWORD)&n, 0, NULL, NULL);
-            if(result != 0 &&WSAGetLastError() != WSAEINTR)
+#ifdef _WIN32
+            n = send((SOCKET)connection->sockfd, buf->data, buf->length, 0);
+            if(n != 0 &&WSAGetLastError() != WSAEINTR)
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
-        } while(result != 0);
-        nWritten += n;
-    }
 #else
-    struct iovec iov[gather_buf.stringsSize];
-    memset(iov, 0, sizeof(struct iovec)*gather_buf.stringsSize);
-    for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
-        iov[i].iov_base = gather_buf.strings[i].data;
-        iov[i].iov_len = gather_buf.strings[i].length;
-        total_len += gather_buf.strings[i].length;
-    }
-    struct msghdr message;
-    memset(&message, 0, sizeof(message));
-    message.msg_iov = iov;
-    message.msg_iovlen = gather_buf.stringsSize;
-    while (nWritten < total_len) {
-        UA_Int32 n = 0;
-        do {
-            n = sendmsg(connection->sockfd, &message, 0);
+            n = send(connection->sockfd, buf->data, buf->length, 0);
             if(n == -1L && errno != EINTR)
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
+#endif
         } while (n == -1L);
         nWritten += n;
     }
-#endif
     return UA_STATUSCODE_GOOD;
 }
 
@@ -88,11 +65,8 @@ static UA_StatusCode socket_recv(UA_Connection *connection, UA_ByteString *respo
     setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv, sizeof(struct timeval));
     int ret = recv(connection->sockfd, (char*)response->data, response->length, 0);
     if(ret <= -1) {
-        if(errno == EAGAIN) {
-            UA_ByteString_deleteMembers(response);
-            UA_ByteString_init(response);
+        if(errno == EAGAIN)
             return UA_STATUSCODE_GOOD;
-        }
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     response->length = ret;
@@ -252,6 +226,7 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     c->close = ServerNetworkLayerTCP_closeConnection;
     c->getBuffer = GetMallocedBuffer;
     c->releaseBuffer = ReleaseMallocedBuffer;
+    c->state = UA_CONNECTION_OPENING;
     struct ConnectionMapping *nm =
         realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
     if(!nm) {

+ 1 - 8
include/ua_connection.h

@@ -28,13 +28,6 @@ extern "C" {
  * @{
  */
 
-/** Used for zero-copy communication. The array of bytestrings is sent over the
-   network as a single buffer. */
-typedef struct UA_ByteStringArray {
-    UA_UInt32      stringsSize;
-    UA_ByteString *strings;
-} UA_ByteStringArray;
-
 typedef enum UA_ConnectionState {
     UA_CONNECTION_OPENING, ///< The socket is open, but the HEL/ACK handshake is not done
     UA_CONNECTION_ESTABLISHED, ///< The socket is open and the connection configured
@@ -73,7 +66,7 @@ struct UA_Connection {
     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
     void (*releaseBuffer)(UA_Connection *connection, UA_ByteString *buf); ///> Release the buffer
-    UA_StatusCode (*write)(UA_Connection *connection, UA_ByteStringArray buf); ///> The bytestrings cannot be reused after sending!
+    UA_StatusCode (*write)(UA_Connection *connection, const UA_ByteString *buf); ///> The bytestrings cannot be reused after sending!
     UA_StatusCode (*recv)(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout); // timeout in milliseconds
     void (*close)(UA_Connection *connection);
 };

+ 20 - 28
src/client/ua_client.c

@@ -91,38 +91,29 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
     UA_TcpHelloMessage_encodeBinary(&hello, &message, &offset);
     UA_TcpHelloMessage_deleteMembers(&hello);
 
-    UA_ByteStringArray buf = {.stringsSize = 1, .strings = &message};
-    UA_StatusCode retval = c->connection.write(&c->connection, buf);
+    UA_StatusCode retval = c->connection.write(&c->connection, &message);
     if(retval)
         return retval;
 
-    UA_ByteString reply;
+    UA_ByteString reply = (UA_ByteString) {.length = 1024, .data = UA_alloca(1024)};
     do {
-        UA_ByteString_newMembers(&reply, 1024);
         retval = c->connection.recv(&c->connection, &reply, c->config.timeout);
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_ByteString_deleteMembers(&reply);
+        if(retval != UA_STATUSCODE_GOOD)
             return retval;
-        }
     } while(reply.length < 0);
 
     offset = 0;
     UA_TcpMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
     UA_TcpAcknowledgeMessage ackMessage;
     retval = UA_TcpAcknowledgeMessage_decodeBinary(&reply, &offset, &ackMessage);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_TcpAcknowledgeMessage_deleteMembers(&ackMessage);
+    if(retval != UA_STATUSCODE_GOOD)
         return retval;
-    }
-    UA_ByteString_deleteMembers(&reply);
     conn->remoteConf.maxChunkCount = ackMessage.maxChunkCount;
     conn->remoteConf.maxMessageSize = ackMessage.maxMessageSize;
     conn->remoteConf.protocolVersion = ackMessage.protocolVersion;
     conn->remoteConf.recvBufferSize = ackMessage.receiveBufferSize;
     conn->remoteConf.sendBufferSize = ackMessage.sendBufferSize;
     conn->state = UA_CONNECTION_ESTABLISHED;
-
-    UA_TcpAcknowledgeMessage_deleteMembers(&ackMessage);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -178,18 +169,20 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
     UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
 
-    UA_ByteStringArray buf = {.stringsSize = 1, .strings = &message};
-    UA_StatusCode retval = client->connection.write(&client->connection, buf);
+    UA_StatusCode retval = client->connection.write(&client->connection, &message);
     if(retval)
         return retval;
 
     // parse the response
     UA_ByteString reply;
     do {
-        UA_ByteString_newMembers(&reply, client->connection.localConf.recvBufferSize);
+        retval = client->connection.getBuffer(&client->connection, &reply,
+                                              client->connection.localConf.recvBufferSize);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
         retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
         if(retval != UA_STATUSCODE_GOOD) {
-            UA_ByteString_deleteMembers(&reply);
+            client->connection.releaseBuffer(&client->connection, &reply);
             return retval;
         }
     } while(reply.length < 0);
@@ -201,15 +194,15 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
     UA_NodeId_decodeBinary(&reply, &offset, &requestType);
 
     if(!UA_NodeId_equal(&requestType, &UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
-                                                        UA_ENCODINGOFFSET_BINARY))) {
-        UA_ByteString_deleteMembers(&reply);
+                                                         UA_ENCODINGOFFSET_BINARY))) {
+        client->connection.releaseBuffer(&client->connection, &reply);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
 
     UA_OpenSecureChannelResponse response;
     UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response);
-    UA_ByteString_deleteMembers(&reply);
+    client->connection.releaseBuffer(&client->connection, &reply);
     retval = response.responseHeader.serviceResult;
 
     if(retval == UA_STATUSCODE_GOOD) {
@@ -260,7 +253,7 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
         UA_calcSizeBinary(request, requestType);
 
     UA_ByteString message;
-    UA_StatusCode retval = UA_ByteString_newMembers(&message, msgHeader.messageHeader.messageSize);
+    UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message, msgHeader.messageHeader.messageSize);
     if(retval != UA_STATUSCODE_GOOD) {
         // todo
     }
@@ -273,9 +266,8 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
     retval |= UA_NodeId_encodeBinary(&requestId, &message, &offset);
     retval |= UA_encodeBinary(request, requestType, &message, &offset);
 
-    UA_ByteStringArray buf = {.stringsSize = 1, .strings = &message};
-    retval = client->connection.write(&client->connection, buf);
-    UA_ByteString_deleteMembers(&message);
+    retval = client->connection.write(&client->connection, &message);
+    client->connection.releaseBuffer(&client->connection, &message);
 
     //TODO: rework to get return value
     if(sendOnly)
@@ -290,10 +282,10 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
     /* Response */
     UA_ByteString reply;
     do {
-        UA_ByteString_newMembers(&reply, client->connection.localConf.recvBufferSize);
+        client->connection.getBuffer(&client->connection, &reply, client->connection.localConf.recvBufferSize);
         retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
         if(retval != UA_STATUSCODE_GOOD) {
-            UA_ByteString_deleteMembers(&reply);
+            client->connection.releaseBuffer(&client->connection, &reply);
             respHeader->serviceResult = retval;
             return;
         }
@@ -308,14 +300,14 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
 
     if(!UA_NodeId_equal(&responseId, &UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
                                                        UA_ENCODINGOFFSET_BINARY))) {
-        UA_ByteString_deleteMembers(&reply);
+        client->connection.releaseBuffer(&client->connection, &reply);
         UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
         respHeader->serviceResult = retval;
         return;
     }
 
     retval = UA_decodeBinary(&reply, &offset, response, responseType);
-    UA_ByteString_deleteMembers(&reply);
+    client->connection.releaseBuffer(&client->connection, &reply);
     if(retval != UA_STATUSCODE_GOOD)
         respHeader->serviceResult = retval;
 }

+ 85 - 87
src/server/ua_server_binary.c

@@ -11,14 +11,6 @@
 /** Max size of messages that are allocated on the stack */
 #define MAX_STACK_MESSAGE 65536
 
-static UA_StatusCode UA_ByteStringArray_deleteMembers(UA_ByteStringArray *stringarray) {
-    if(!stringarray)
-        return UA_STATUSCODE_BADINTERNALERROR;
-    for(UA_UInt32 i = 0; i < stringarray->stringsSize; i++)
-        UA_String_deleteMembers(&stringarray->strings[i]);
-    return UA_STATUSCODE_GOOD;
-}
-
 static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size_t *pos) {
     UA_TcpHelloMessage helloMessage;
     if(UA_TcpHelloMessage_decodeBinary(msg, pos, &helloMessage) != UA_STATUSCODE_GOOD) {
@@ -32,6 +24,7 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size
     connection->remoteConf.recvBufferSize = helloMessage.receiveBufferSize;
     connection->remoteConf.sendBufferSize = helloMessage.sendBufferSize;
     connection->state = UA_CONNECTION_ESTABLISHED;
+    UA_TcpHelloMessage_deleteMembers(&helloMessage);
 
     // build acknowledge response
     UA_TcpAcknowledgeMessage ackMessage;
@@ -43,18 +36,18 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size
 
     UA_TcpMessageHeader ackHeader;
     ackHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_ACKF;
-    ackHeader.messageSize = UA_TcpAcknowledgeMessage_calcSizeBinary(&ackMessage) +
-        UA_TcpMessageHeader_calcSizeBinary(&ackHeader);
+    ackHeader.messageSize = UA_TcpMessageHeader_calcSizeBinary(&ackHeader) 
+        + UA_TcpAcknowledgeMessage_calcSizeBinary(&ackMessage);
+
+    UA_ByteString ack_msg;
+    if(connection->getBuffer(connection, &ack_msg, ackHeader.messageSize) != UA_STATUSCODE_GOOD)
+        return;
 
-    // The message is on the stack. That's ok since ack is very small.
-    UA_ByteString ack_msg = (UA_ByteString){ .length = ackHeader.messageSize,
-                                             .data = UA_alloca(ackHeader.messageSize) };
     size_t tmpPos = 0;
     UA_TcpMessageHeader_encodeBinary(&ackHeader, &ack_msg, &tmpPos);
     UA_TcpAcknowledgeMessage_encodeBinary(&ackMessage, &ack_msg, &tmpPos);
-    UA_ByteStringArray answer_buf = { .stringsSize = 1, .strings = &ack_msg };
-    connection->write(connection, answer_buf);
-    UA_TcpHelloMessage_deleteMembers(&helloMessage);
+    connection->write(connection, &ack_msg);
+    connection->releaseBuffer(connection, &ack_msg);
 }
 
 static void processOPN(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg,
@@ -91,6 +84,7 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     UA_OpenSecureChannelResponse p;
     UA_OpenSecureChannelResponse_init(&p);
     Service_OpenSecureChannel(server, connection, &r, &p);
+    UA_OpenSecureChannelRequest_deleteMembers(&r);
 
     UA_SecureConversationMessageHeader respHeader;
     respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
@@ -107,10 +101,8 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
         + UA_NodeId_calcSizeBinary(&responseType)
         + UA_OpenSecureChannelResponse_calcSizeBinary(&p);
 
-    UA_ByteString resp_msg = (UA_ByteString){
-        .length = respHeader.messageHeader.messageSize,
-        .data = UA_alloca(respHeader.messageHeader.messageSize)
-    };
+    UA_ByteString resp_msg;
+    retval = connection->getBuffer(connection, &resp_msg, respHeader.messageHeader.messageSize);
 
     size_t tmpPos = 0;
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
@@ -119,10 +111,10 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos);
     UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos);
 
-    UA_OpenSecureChannelRequest_deleteMembers(&r);
     UA_OpenSecureChannelResponse_deleteMembers(&p);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
-    connection->write(connection, (UA_ByteStringArray){ .stringsSize = 1, .strings = &resp_msg });
+    connection->write(connection, &resp_msg);
+    connection->releaseBuffer(connection, &resp_msg);
 }
 
 static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r) {
@@ -146,11 +138,14 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
             r.responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID; \
         else                                                            \
             Service_##TYPE(server, clientSession, &p, &r);              \
-        connection->getBuffer(connection, message, UA_##TYPE##Response_calcSizeBinary(&r)); \
-        UA_##TYPE##Response_encodeBinary(&r, message, &sendOffset);     \
         UA_##TYPE##Request_deleteMembers(&p);                           \
+        retval = connection->getBuffer(connection, &message, headerSize + UA_##TYPE##Response_calcSizeBinary(&r)); \
+        if(retval != UA_STATUSCODE_GOOD) {                              \
+            UA_##TYPE##Response_deleteMembers(&r);                      \
+            return;                                                     \
+        }                                                               \
+        UA_##TYPE##Response_encodeBinary(&r, &message, &messagePos);    \
         UA_##TYPE##Response_deleteMembers(&r);                          \
-        responseType = requestType.identifier.numeric + 3;              \
     } while(0)
 
 static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) {
@@ -188,25 +183,38 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         clientSession = &anonymousSession;
 #endif
 
-    // 3) Read the nodeid of the request
+    // 3) Build the header and compute the header size
+    UA_SecureConversationMessageHeader respHeader;
+    respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
+    respHeader.messageHeader.messageSize = 0;
+    respHeader.secureChannelId = clientChannel->securityToken.channelId;
+
+    UA_SymmetricAlgorithmSecurityHeader symSecHeader;
+    symSecHeader.tokenId = clientChannel->securityToken.tokenId;
+
+    UA_SequenceHeader seqHeader;
+    seqHeader.sequenceNumber = clientChannel->sequenceNumber;
+    seqHeader.requestId = clientChannel->requestId;
+
+    // 4) process the request
+    UA_ByteString message;
     UA_NodeId requestType;
     if(UA_NodeId_decodeBinary(msg, pos, &requestType))
         return;
     if(requestType.identifierType != UA_NODEIDTYPE_NUMERIC) {
-        // That must not happen. The requestType does not have to be deleted at the end.
         UA_NodeId_deleteMembers(&requestType);
         return;
     }
 
-    // 4) process the request
-    UA_ByteString responseBufs[2]; // 0->header, 1->response payload
-    UA_UInt32 responseType;
-    UA_ByteString *header = &responseBufs[0];
-    UA_ByteString *message = &responseBufs[1];
-    size_t sendOffset = 0;
-
-    //subtract UA_ENCODINGOFFSET_BINARY for binary encoding, if retval is set, this forces the default path
-    switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY + retval) {
+    UA_NodeId response_nodeid = UA_NODEID_NUMERIC(0, requestType.identifier.numeric + 3);
+    UA_UInt32 headerSize = UA_SecureConversationMessageHeader_calcSizeBinary(&respHeader)
+        + UA_SymmetricAlgorithmSecurityHeader_calcSizeBinary(&symSecHeader)
+        + UA_SequenceHeader_calcSizeBinary(&seqHeader)
+        + UA_NodeId_calcSizeBinary(&response_nodeid);
+    size_t messagePos = headerSize;
+
+    //subtract UA_ENCODINGOFFSET_BINARY for binary encoding
+    switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY) {
     case UA_NS0ID_GETENDPOINTSREQUEST: {
         UA_GetEndpointsRequest  p;
         UA_GetEndpointsResponse r;
@@ -215,11 +223,14 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         UA_GetEndpointsResponse_init(&r);
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_GetEndpoints(server, &p, &r);
-        connection->getBuffer(connection, message, UA_GetEndpointsResponse_calcSizeBinary(&r));
-        UA_GetEndpointsResponse_encodeBinary(&r, message, &sendOffset);
         UA_GetEndpointsRequest_deleteMembers(&p);
+        retval = connection->getBuffer(connection, &message, headerSize + UA_GetEndpointsResponse_calcSizeBinary(&r));
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_GetEndpointsResponse_deleteMembers(&r);
+            return;
+        }
+        UA_GetEndpointsResponse_encodeBinary(&r, &message, &messagePos);
         UA_GetEndpointsResponse_deleteMembers(&r);
-        responseType = requestType.identifier.numeric + 3;
         break;
     }
 
@@ -231,11 +242,14 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         UA_FindServersResponse_init(&r);
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_FindServers(server, &p, &r);
-        connection->getBuffer(connection, message, UA_FindServersResponse_calcSizeBinary(&r));
-        UA_FindServersResponse_encodeBinary(&r, message, &sendOffset);
         UA_FindServersRequest_deleteMembers(&p);
+        retval = connection->getBuffer(connection, &message, headerSize + UA_FindServersResponse_calcSizeBinary(&r));
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_FindServersResponse_deleteMembers(&r);
+            return;
+        }
+        UA_FindServersResponse_encodeBinary(&r, &message, &messagePos);
         UA_FindServersResponse_deleteMembers(&r);
-        responseType = requestType.identifier.numeric + 3;
         break;
     }
 
@@ -247,11 +261,14 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         UA_CreateSessionResponse_init(&r);
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_CreateSession(server, clientChannel, &p, &r);
-        connection->getBuffer(connection, message, UA_CreateSessionResponse_calcSizeBinary(&r));
-        UA_CreateSessionResponse_encodeBinary(&r, message, &sendOffset);
         UA_CreateSessionRequest_deleteMembers(&p);
+        retval = connection->getBuffer(connection, &message, headerSize + UA_CreateSessionResponse_calcSizeBinary(&r));
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_CreateSessionResponse_deleteMembers(&r);
+            return;
+        }
+        UA_CreateSessionResponse_encodeBinary(&r, &message, &messagePos);
         UA_CreateSessionResponse_deleteMembers(&r);
-        responseType = requestType.identifier.numeric + 3;
         break;
     }
 
@@ -263,11 +280,14 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         UA_ActivateSessionResponse_init(&r);
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_ActivateSession(server, clientChannel, &p, &r);
-        connection->getBuffer(connection, message, UA_ActivateSessionResponse_calcSizeBinary(&r));
-        UA_ActivateSessionResponse_encodeBinary(&r, message, &sendOffset);
         UA_ActivateSessionRequest_deleteMembers(&p);
+        retval = connection->getBuffer(connection, &message, headerSize + UA_ActivateSessionResponse_calcSizeBinary(&r));
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_ActivateSessionResponse_deleteMembers(&r);
+            return;
+        }
+        UA_ActivateSessionResponse_encodeBinary(&r, &message, &messagePos);
         UA_ActivateSessionResponse_deleteMembers(&r);
-        responseType = requestType.identifier.numeric + 3;
         break;
     }
 
@@ -298,6 +318,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
         INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
         break;
+
     default: {
         UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION, "Unknown request: NodeId(ns=%d, i=%d)",
                     requestType.namespaceIndex, requestType.identifier.numeric);
@@ -312,54 +333,31 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         if(retval != UA_STATUSCODE_GOOD)
             r.serviceResult = retval;
 #endif
-        connection->getBuffer(connection, message, UA_ResponseHeader_calcSizeBinary(&r));
-        UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
         UA_RequestHeader_deleteMembers(&p);
+        retval = connection->getBuffer(connection, &message, headerSize + UA_ResponseHeader_calcSizeBinary(&r));
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_ResponseHeader_deleteMembers(&r);
+            return;
+        }
+        UA_ResponseHeader_encodeBinary(&r, &message, &messagePos);
         UA_ResponseHeader_deleteMembers(&r);
-        responseType = UA_NS0ID_RESPONSEHEADER + UA_ENCODINGOFFSET_BINARY;
+        response_nodeid = UA_NODEID_NUMERIC(0, UA_NS0ID_RESPONSEHEADER + UA_ENCODINGOFFSET_BINARY);
         break;
     }
     }
 
-    // 5) Build the header
-    UA_SecureConversationMessageHeader respHeader;
-    respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-    respHeader.messageHeader.messageSize = 0;
-    respHeader.secureChannelId = clientChannel->securityToken.channelId;
-
-    UA_SymmetricAlgorithmSecurityHeader symSecHeader;
-    symSecHeader.tokenId = clientChannel->securityToken.tokenId;
-
-    UA_SequenceHeader seqHeader;
-    seqHeader.sequenceNumber = clientChannel->sequenceNumber;
-    seqHeader.requestId = clientChannel->requestId;
-
-    UA_NodeId response_nodeid = { .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
-        .identifier.numeric = responseType };
-
-    UA_UInt32 headerSize =
-        UA_SecureConversationMessageHeader_calcSizeBinary(&respHeader)
-        + UA_SymmetricAlgorithmSecurityHeader_calcSizeBinary(&symSecHeader)
-        + UA_SequenceHeader_calcSizeBinary(&seqHeader)
-        + UA_NodeId_calcSizeBinary(&response_nodeid);
-    respHeader.messageHeader.messageSize = headerSize + message->length;
-
-    size_t rpos = 0;
-    connection->getBuffer(connection, header, headerSize);
-    UA_SecureConversationMessageHeader_encodeBinary(&respHeader, header, &rpos);
-    UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, header, &rpos);
-    UA_SequenceHeader_encodeBinary(&seqHeader, header, &rpos);
-    UA_NodeId_encodeBinary(&response_nodeid, header, &rpos);
+    messagePos = 0;
+    respHeader.messageHeader.messageSize = message.length;
+    UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &message, &messagePos);
+    UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, &message, &messagePos);
+    UA_SequenceHeader_encodeBinary(&seqHeader, &message, &messagePos);
+    UA_NodeId_encodeBinary(&response_nodeid, &message, &messagePos);
 
     // todo: sign & encrypt
 
-    // 6) Send it over the wire.
-    UA_ByteStringArray responseBufArray;
-    responseBufArray.strings = responseBufs;
-    responseBufArray.stringsSize = 2;
-    connection->write(connection, responseBufArray);
-    connection->releaseBuffer(connection, header);
-    connection->releaseBuffer(connection, message);
+    // 5) Send it over the wire.
+    connection->write(connection, &message);
+    connection->releaseBuffer(connection, &message);
 }
 
 static void processCLO(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) {

+ 3 - 2
src/server/ua_server_worker.c

@@ -18,13 +18,14 @@
 #define BATCHSIZE 20 // max size of worklists that are dispatched to workers
 
 static void processWork(UA_Server *server, UA_WorkItem *work, UA_Int32 workSize) {
-    for(UA_Int32 i = 0;i<workSize;i++) {
+    for(UA_Int32 i = 0; i < workSize; i++) {
         UA_WorkItem *item = &work[i];
         switch(item->type) {
         case UA_WORKITEMTYPE_BINARYNETWORKMESSAGE:
             UA_Server_processBinaryMessage(server, item->work.binaryNetworkMessage.connection,
                                            &item->work.binaryNetworkMessage.message);
-            UA_free(item->work.binaryNetworkMessage.message.data);
+            item->work.binaryNetworkMessage.connection->releaseBuffer(item->work.binaryNetworkMessage.connection,
+                                                                      &item->work.binaryNetworkMessage.message);
             break;
 
         case UA_WORKITEMTYPE_METHODCALL:

+ 2 - 1
tests/check_server_interaction_fileinput.c

@@ -15,7 +15,8 @@ UA_UInt32 read_count = 0;
 UA_UInt32 max_reads;
 char **filenames;
 
-static void writeCallback(void *handle, UA_ByteStringArray buf) {
+static UA_StatusCode writeCallback(void *handle, UA_ByteString *buf) {
+    return UA_STATUSCODE_GOOD;
 }
 
 static void readCallback(void) {

+ 7 - 7
tests/testing_networklayers.c

@@ -4,19 +4,19 @@
 #include <assert.h>
 #include "testing_networklayers.h"
 
-typedef struct {
+typedef struct NetworkLayer_FileInput {
 	UA_Connection connection;
     UA_UInt32 files;
     char **filenames;
     UA_UInt32 files_read;
-    void (*writeCallback)(void *, UA_ByteStringArray buf);
+    UA_StatusCode (*writeCallback)(struct NetworkLayer_FileInput *handle, const UA_ByteString *buf);
     void (*readCallback)(void);
     void *callbackHandle;
 } NetworkLayer_FileInput;
 
 /** Accesses only the sockfd in the handle. Can be run from parallel threads. */
-static UA_StatusCode writeCallback(NetworkLayer_FileInput *handle, UA_ByteStringArray gather_buf) {
-    handle->writeCallback(handle->callbackHandle, gather_buf);
+static UA_StatusCode writeCallback(NetworkLayer_FileInput *handle, const UA_ByteString *buf) {
+    handle->writeCallback(handle->callbackHandle, buf);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -73,7 +73,7 @@ static void NetworkLayer_FileInput_delete(NetworkLayer_FileInput *layer) {
 
 UA_ServerNetworkLayer
 ServerNetworkLayerFileInput_new(UA_UInt32 files, char **filenames, void(*readCallback)(void),
-                                void(*writeCallback) (void*, UA_ByteStringArray buf),
+                                UA_StatusCode (*writeCallback) (void*, UA_ByteString *buf),
                                 void *callbackHandle)
 {
     NetworkLayer_FileInput *layer = malloc(sizeof(NetworkLayer_FileInput));
@@ -81,13 +81,13 @@ ServerNetworkLayerFileInput_new(UA_UInt32 files, char **filenames, void(*readCal
     layer->connection.localConf = UA_ConnectionConfig_standard;
     layer->connection.channel = (void*)0;
     layer->connection.close = (void (*)(UA_Connection*))closeCallback;
-    layer->connection.write = (UA_StatusCode (*)(UA_Connection*, UA_ByteStringArray))writeCallback;
+    layer->connection.write = (UA_StatusCode (*)(UA_Connection*, const UA_ByteString*))writeCallback;
 
     layer->files = files;
     layer->filenames = filenames;
     layer->files_read = 0;
     layer->readCallback = readCallback;
-    layer->writeCallback = writeCallback;
+    layer->writeCallback = (UA_StatusCode(*)(struct NetworkLayer_FileInput *handle, const UA_ByteString *buf)) writeCallback;
     layer->callbackHandle = callbackHandle;
     
     UA_ServerNetworkLayer nl;

+ 1 - 1
tests/testing_networklayers.h

@@ -10,7 +10,7 @@
 /** @brief Create the TCP networklayer and listen to the specified port */
 UA_ServerNetworkLayer
 ServerNetworkLayerFileInput_new(UA_UInt32 files, char **filenames, void(*readCallback)(void),
-                                void(*writeCallback) (void*, UA_ByteStringArray buf),
+                                UA_StatusCode (*writeCallback) (void*, UA_ByteString *buf),
                                 void *callbackHandle);
 
 #endif /* TESTING_NETWORKLAYERS_H_ */