Sfoglia il codice sorgente

Added UA_SecureChannel_sendBinaryResponse

That can be used to send responses async outside of the main switch in ua_server_binary.c
Julius Pfrommer 9 anni fa
parent
commit
3220a651db
4 ha cambiato i file con 240 aggiunte e 315 eliminazioni
  1. 120 175
      src/client/ua_client.c
  2. 60 117
      src/server/ua_server_binary.c
  3. 57 20
      src/ua_securechannel.c
  4. 3 3
      src/ua_securechannel.h

+ 120 - 175
src/client/ua_client.c

@@ -1,29 +1,19 @@
-#include <ua_types_generated.h>
+#include "ua_types_generated.h"
 #include "ua_client.h"
 #include "ua_nodeids.h"
-#include "ua_types.h"
+#include "ua_securechannel.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_transport_generated.h"
 
 struct UA_Client {
     /* Connection */
     UA_Connection connection;
+    UA_SecureChannel channel;
     UA_String endpointUrl;
-
-    UA_UInt32 sequenceNumber;
     UA_UInt32 requestId;
 
-    /* Secure Channel */
-    UA_ChannelSecurityToken securityToken;
-    UA_ByteString clientNonce;
-    UA_ByteString serverNonce;
-    /* UA_SequenceHeader sequenceHdr; */
-    /* UA_NodeId authenticationToken; */
-
-    /* IdentityToken */
-    UA_UserTokenPolicy token;
-
     /* Session */
+    UA_UserTokenPolicy token;
     UA_NodeId sessionId;
     UA_NodeId authenticationToken;
 
@@ -42,37 +32,27 @@ UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
     UA_Client *client = UA_malloc(sizeof(UA_Client));
     if(!client)
         return UA_NULL;
-    client->config = config;
-    client->logger = logger;
-    UA_String_init(&client->endpointUrl);
-    UA_Connection_init(&client->connection);
 
-    client->sequenceNumber = 0;
+    UA_Connection_init(&client->connection);
+    UA_SecureChannel_init(&client->channel);
+    client->channel.connection = &client->connection;
+    UA_String_init(&client->endpointUrl);
     client->requestId = 0;
 
-    client->scExpiresAt = 0;
-
-    /* Secure Channel */
-    UA_ChannelSecurityToken_deleteMembers(&client->securityToken);
-    UA_ByteString_init(&client->clientNonce);
-    UA_ByteString_init(&client->serverNonce);
-    
     UA_NodeId_init(&client->authenticationToken);
 
+    client->logger = logger;
+    client->config = config;
+    client->scExpiresAt = 0;
+    
     return client;
 }
 
 void UA_Client_delete(UA_Client* client){
     UA_Connection_deleteMembers(&client->connection);
-    UA_Connection_deleteMembers(&client->connection);
+    UA_SecureChannel_deleteMembersCleanup(&client->channel);
     UA_String_deleteMembers(&client->endpointUrl);
-
-    /* Secure Channel */
-    UA_ByteString_deleteMembers(&client->clientNonce);
-    UA_ByteString_deleteMembers(&client->serverNonce);
-
     UA_UserTokenPolicy_deleteMembers(&client->token);
-
     free(client);
 }
 
@@ -132,16 +112,12 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
 }
 
 static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
-    UA_ByteString_deleteMembers(&client->clientNonce); // if the handshake is repeated
-    UA_ByteString_newMembers(&client->clientNonce, 1);
-    client->clientNonce.data[0] = 0;
-
     UA_SecureConversationMessageHeader messageHeader;
     messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
     messageHeader.secureChannelId = 0;
 
     UA_SequenceHeader seqHeader;
-    seqHeader.sequenceNumber = ++client->sequenceNumber;
+    seqHeader.sequenceNumber = ++client->channel.sequenceNumber;
     seqHeader.requestId = ++client->requestId;
 
     UA_AsymmetricAlgorithmSecurityHeader asymHeader;
@@ -160,7 +136,8 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
         opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW;
     } else {
         opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
-        UA_ByteString_copy(&client->clientNonce, &opnSecRq.clientNonce);
+        UA_SecureChannel_generateNonce(&client->channel.clientNonce);
+        UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce);
         opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
     }
 
@@ -225,9 +202,9 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     retval = response.responseHeader.serviceResult;
 
     if(!renew && retval == UA_STATUSCODE_GOOD) {
-        UA_ChannelSecurityToken_copy(&response.securityToken, &client->securityToken);
-        UA_ByteString_deleteMembers(&client->serverNonce); // if the handshake is repeated
-        UA_ByteString_copy(&response.serverNonce, &client->serverNonce);
+        UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel.securityToken);
+        UA_ByteString_deleteMembers(&client->channel.serverNonce); // if the handshake is repeated
+        UA_ByteString_copy(&response.serverNonce, &client->channel.serverNonce);
     }
 
     UA_OpenSecureChannelResponse_deleteMembers(&response);
@@ -238,78 +215,28 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
 
 /** If the request fails, then the response is cast to UA_ResponseHeader (at the beginning of every
     response) and filled with the appropriate error code */
-static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *requestType,
-                               void *response, const UA_DataType *responseType, UA_Client *client,
-                               UA_Boolean sendOnly) {
-
-    //check if sc needs to be renewed
-    if(client->scExpiresAt-UA_DateTime_now() <= client->config.timeToRenewSecureChannel * 10000){ //less than 3 seconds left to expire -> renew
+static void synchronousRequest(UA_Client *client, const void *request, const UA_DataType *requestType,
+                               void *response, const UA_DataType *responseType) {
+    /* Check if sc needs to be renewed */
+    if(client->scExpiresAt - UA_DateTime_now() <= client->config.timeToRenewSecureChannel * 10000 )
         UA_Client_renewSecureChannel(client);
-    }
 
-    if(response)
-        UA_init(response, responseType);
-    else
+    if(!response)
         return;
+    UA_init(response, responseType);
 
-    UA_NodeId_copy(&client->authenticationToken, &request->authenticationToken);
-
-    UA_SecureConversationMessageHeader msgHeader;
-    if(sendOnly)
-        msgHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_CLOF;
-    else
-        msgHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-    msgHeader.secureChannelId = client->securityToken.channelId;
-
-    UA_SymmetricAlgorithmSecurityHeader symHeader;
-    symHeader.tokenId = client->securityToken.tokenId;
-    
-    UA_SequenceHeader seqHeader;
-    seqHeader.sequenceNumber = ++client->sequenceNumber;
-    seqHeader.requestId = ++client->requestId;
-
-    UA_NodeId requestId = UA_NODEID_NUMERIC(0, requestType->typeId.identifier.numeric +
-                                           UA_ENCODINGOFFSET_BINARY);
-
-    msgHeader.messageHeader.messageSize =
-        UA_SecureConversationMessageHeader_calcSizeBinary(&msgHeader) +
-        UA_SymmetricAlgorithmSecurityHeader_calcSizeBinary(&symHeader) +
-        UA_SequenceHeader_calcSizeBinary(&seqHeader) +
-        UA_NodeId_calcSizeBinary(&requestId) +
-        UA_calcSizeBinary(request, requestType);
-
-    UA_ByteString message;
-    UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message, msgHeader.messageHeader.messageSize);
-    if(retval != UA_STATUSCODE_GOOD) {
-        // todo: print error message
-        return;
-    }
-
-    size_t offset = 0;
-    retval |= UA_SecureConversationMessageHeader_encodeBinary(&msgHeader, &message, &offset);
-    retval |= UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symHeader, &message, &offset);
-    retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
-
-    retval |= UA_NodeId_encodeBinary(&requestId, &message, &offset);
-    retval |= UA_encodeBinary(request, requestType, &message, &offset);
-
-    retval |= client->connection.write(&client->connection, &message);
-
+    /* Send the request */
+    UA_UInt32 requestId = ++client->requestId;
+    UA_StatusCode retval = UA_SecureChannel_sendBinaryMessage(&client->channel, requestId,
+                                                              request, requestType);
     UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response;
-
-    client->connection.releaseBuffer(&client->connection, &message);
-
-    if(retval != UA_STATUSCODE_GOOD) {
-        //send failed
+    if(retval) {
         respHeader->serviceResult = retval;
         return;
     }
 
-    //TODO: rework to get return value
-    if(sendOnly)
-        return;
-
-    /* Response */
+    /* Retrieve the response */
+    // Todo: push this into the generic securechannel implementation for client and server
     UA_ByteString reply;
     UA_ByteString_init(&reply);
     do {
@@ -320,18 +247,22 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
         }
     } while(retval != UA_STATUSCODE_GOOD);
 
-    offset = 0;
+    size_t offset = 0;
+    UA_SecureConversationMessageHeader msgHeader;
     retval |= UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &msgHeader);
+    UA_SymmetricAlgorithmSecurityHeader symHeader;
     retval |= UA_SymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &symHeader);
+    UA_SequenceHeader seqHeader;
     retval |= UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
     UA_NodeId responseId;
     retval |= UA_NodeId_decodeBinary(&reply, &offset, &responseId);
     UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
                                                  UA_ENCODINGOFFSET_BINARY);
-    if(!UA_NodeId_equal(&responseId, &expectedNodeId)) {
+    if(!UA_NodeId_equal(&responseId, &expectedNodeId) || seqHeader.requestId != requestId) {
+        // Todo: we need to demux responses since a publish responses may come at any time
         client->connection.releaseBuffer(&client->connection, &reply);
         UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
-        respHeader->serviceResult = retval;
+        respHeader->serviceResult = UA_STATUSCODE_BADINTERNALERROR;
         return;
     }
 
@@ -341,11 +272,6 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
         respHeader->serviceResult = retval;
 }
 
-static void synchronousRequest(void *request, const UA_DataType *requestType, void *response,
-                               const UA_DataType *responseType, UA_Client *client) {
-    sendReceiveRequest(request, requestType, response, responseType, client, UA_FALSE);
-}
-
 static UA_StatusCode ActivateSession(UA_Client *client) {
     UA_ActivateSessionRequest request;
     UA_ActivateSessionRequest_init(&request);
@@ -369,9 +295,8 @@ static UA_StatusCode ActivateSession(UA_Client *client) {
     UA_ByteString_encodeBinary(&identityToken.policyId,&request.userIdentityToken.body,&offset);
 
     UA_ActivateSessionResponse response;
-    synchronousRequest(&request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
-                       &response, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE],
-                       client);
+    synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
+                       &response, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]);
 
     UA_AnonymousIdentityToken_deleteMembers(&identityToken);
     UA_ActivateSessionRequest_deleteMembers(&request);
@@ -382,41 +307,37 @@ static UA_StatusCode ActivateSession(UA_Client *client) {
 static UA_StatusCode EndpointsHandshake(UA_Client *client) {
     UA_GetEndpointsRequest request;
     UA_GetEndpointsRequest_init(&request);
-
-    // todo: is this needed for all requests?
     UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
-
     request.requestHeader.timestamp = UA_DateTime_now();
     request.requestHeader.timeoutHint = 10000;
     UA_String_copy(&client->endpointUrl, &request.endpointUrl);
-
     request.profileUrisSize = 1;
     request.profileUris = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], request.profileUrisSize);
-    request.profileUris[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
+    *request.profileUris = UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
 
     UA_GetEndpointsResponse response;
     UA_GetEndpointsResponse_init(&response);
-    synchronousRequest(&request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
-                       &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE],
-                       client);
+    synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
+                       &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);
 
     UA_Boolean endpointFound = UA_FALSE;
     UA_Boolean tokenFound = UA_FALSE;
     for(UA_Int32 i=0; i<response.endpointsSize; ++i){
         UA_EndpointDescription* endpoint = &response.endpoints[i];
         /* look out for an endpoint without security */
-        if(UA_String_equal(&endpoint->securityPolicyUri, &UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"))){
-            endpointFound = UA_TRUE;
-            /* endpoint with no security found */
-            /* look for a user token policy with an anonymous token */
-            for(UA_Int32 j=0; j<endpoint->userIdentityTokensSize; ++j){
-                UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j];
-                if(userToken->tokenType == UA_USERTOKENTYPE_ANONYMOUS){
-                    tokenFound = UA_TRUE;
-                    UA_UserTokenPolicy_copy(userToken, &client->token);
-                    break;
-                }
-            }
+        if(!UA_String_equal(&endpoint->securityPolicyUri,
+                            &UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None")))
+            continue;
+        endpointFound = UA_TRUE;
+        /* endpoint with no security found */
+        /* look for a user token policy with an anonymous token */
+        for(UA_Int32 j=0; j<endpoint->userIdentityTokensSize; ++j) {
+            UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j];
+            if(userToken->tokenType != UA_USERTOKENTYPE_ANONYMOUS)
+                continue;
+            tokenFound = UA_TRUE;
+            UA_UserTokenPolicy_copy(userToken, &client->token);
+            break;
         }
     }
 
@@ -424,15 +345,14 @@ static UA_StatusCode EndpointsHandshake(UA_Client *client) {
     UA_GetEndpointsResponse_deleteMembers(&response);
 
     if(!endpointFound){
-        printf("No suitable endpoint found\n");
+        UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No suitable endpoint found");
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     if(!tokenFound){
-        printf("No anonymous token found\n");
+        UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No anonymous token found");
         return UA_STATUSCODE_BADINTERNALERROR;
     }
-
-    return response.responseHeader.serviceResult; // not deleted
+    return response.responseHeader.serviceResult;
 }
 
 static UA_StatusCode SessionHandshake(UA_Client *client) {
@@ -441,22 +361,16 @@ static UA_StatusCode SessionHandshake(UA_Client *client) {
 
     // todo: is this needed for all requests?
     UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
-
     request.requestHeader.timestamp = UA_DateTime_now();
     request.requestHeader.timeoutHint = 10000;
-    UA_ByteString_copy(&client->clientNonce, &request.clientNonce);
+    UA_ByteString_copy(&client->channel.clientNonce, &request.clientNonce);
     request.requestedSessionTimeout = 1200000;
     request.maxResponseMessageSize = UA_INT32_MAX;
 
-    /* UA_String_copy(endpointUrl, &rq.endpointUrl); */
-    /* UA_String_copycstring("mysession", &rq.sessionName); */
-    /* UA_String_copycstring("abcd", &rq.clientCertificate); */
-
     UA_CreateSessionResponse response;
     UA_CreateSessionResponse_init(&response);
-    synchronousRequest(&request, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
-                       &response, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE],
-                       client);
+    synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
+                       &response, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]);
 
     UA_NodeId_copy(&response.authenticationToken, &client->authenticationToken);
 
@@ -474,9 +388,8 @@ static UA_StatusCode CloseSession(UA_Client *client) {
     request.deleteSubscriptions = UA_TRUE;
     UA_NodeId_copy(&client->authenticationToken, &request.requestHeader.authenticationToken);
     UA_CreateSessionResponse response;
-    synchronousRequest(&request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
-                       &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE],
-                       client);
+    synchronousRequest(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
+                       &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]);
 
     UA_CloseSessionRequest_deleteMembers(&request);
     UA_CloseSessionResponse_deleteMembers(&response);
@@ -484,18 +397,50 @@ static UA_StatusCode CloseSession(UA_Client *client) {
 }
 
 static UA_StatusCode CloseSecureChannel(UA_Client *client) {
+    UA_SecureChannel *channel = &client->channel;
     UA_CloseSecureChannelRequest request;
     UA_CloseSecureChannelRequest_init(&request);
-
     request.requestHeader.requestHandle = 1; //TODO: magic number?
     request.requestHeader.timestamp = UA_DateTime_now();
     request.requestHeader.timeoutHint = 10000;
     request.requestHeader.authenticationToken = client->authenticationToken;
-    sendReceiveRequest(&request.requestHeader, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST], UA_NULL, UA_NULL,
-                       client, UA_TRUE);
 
-    return UA_STATUSCODE_GOOD;
+    UA_SecureConversationMessageHeader msgHeader;
+    msgHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_CLOF;
+    msgHeader.secureChannelId = client->channel.securityToken.channelId;
+
+    UA_SymmetricAlgorithmSecurityHeader symHeader;
+    symHeader.tokenId = channel->securityToken.tokenId;
+    
+    UA_SequenceHeader seqHeader;
+    seqHeader.sequenceNumber = ++channel->sequenceNumber;
+    seqHeader.requestId = ++client->requestId;
+
+    UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CLOSESECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
 
+    msgHeader.messageHeader.messageSize =
+        UA_SecureConversationMessageHeader_calcSizeBinary(&msgHeader) +
+        UA_SymmetricAlgorithmSecurityHeader_calcSizeBinary(&symHeader) +
+        UA_SequenceHeader_calcSizeBinary(&seqHeader) +
+        UA_NodeId_calcSizeBinary(&typeId) +
+        UA_calcSizeBinary(&request, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST]);
+
+    UA_ByteString message;
+    UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message,
+                                                        msgHeader.messageHeader.messageSize);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    size_t offset = 0;
+    retval |= UA_SecureConversationMessageHeader_encodeBinary(&msgHeader, &message, &offset);
+    retval |= UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symHeader, &message, &offset);
+    retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
+    retval |= UA_NodeId_encodeBinary(&typeId, &message, &offset);
+    retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST], &message, &offset);
+    if(retval == UA_STATUSCODE_GOOD)
+        retval = client->connection.write(&client->connection, &message);
+    client->connection.releaseBuffer(&client->connection, &message);
+    return retval;
 }
 
 /*************************/
@@ -538,29 +483,29 @@ UA_StatusCode UA_Client_renewSecureChannel(UA_Client *client) {
 
 UA_ReadResponse UA_Client_read(UA_Client *client, UA_ReadRequest *request) {
     UA_ReadResponse response;
-    synchronousRequest(request, &UA_TYPES[UA_TYPES_READREQUEST], &response,
-                       &UA_TYPES[UA_TYPES_READRESPONSE], client);
+    synchronousRequest(client, request, &UA_TYPES[UA_TYPES_READREQUEST], &response,
+                       &UA_TYPES[UA_TYPES_READRESPONSE]);
     return response;
 }
 
 UA_WriteResponse UA_Client_write(UA_Client *client, UA_WriteRequest *request) {
     UA_WriteResponse response;
-    synchronousRequest(request, &UA_TYPES[UA_TYPES_WRITEREQUEST], &response,
-                       &UA_TYPES[UA_TYPES_WRITERESPONSE], client);
+    synchronousRequest(client, request, &UA_TYPES[UA_TYPES_WRITEREQUEST], &response,
+                       &UA_TYPES[UA_TYPES_WRITERESPONSE]);
     return response;
 }
 
 UA_BrowseResponse UA_Client_browse(UA_Client *client, UA_BrowseRequest *request) {
     UA_BrowseResponse response;
-    synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
-                       &UA_TYPES[UA_TYPES_BROWSERESPONSE], client);
+    synchronousRequest(client, request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
+                       &UA_TYPES[UA_TYPES_BROWSERESPONSE]);
     return response;
 }
 
 UA_BrowseNextResponse UA_Client_browseNext(UA_Client *client, UA_BrowseNextRequest *request) {
     UA_BrowseNextResponse response;
-    synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], &response,
-                       &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE], client);
+    synchronousRequest(client, request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], &response,
+                       &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]);
     return response;
 }
 
@@ -568,35 +513,35 @@ UA_TranslateBrowsePathsToNodeIdsResponse
     UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
                                                      UA_TranslateBrowsePathsToNodeIdsRequest *request) {
     UA_TranslateBrowsePathsToNodeIdsResponse response;
-    synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
-                       &UA_TYPES[UA_TYPES_BROWSERESPONSE], client);
+    synchronousRequest(client, request, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST],
+                       &response, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]);
     return response;
 }
 
 UA_AddNodesResponse UA_Client_addNodes(UA_Client *client, UA_AddNodesRequest *request) {
     UA_AddNodesResponse response;
-    synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
-                       &UA_TYPES[UA_TYPES_BROWSERESPONSE], client);
+    synchronousRequest(client, request, &UA_TYPES[UA_TYPES_ADDNODESREQUEST],
+                       &response, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]);
     return response;
 }
 
 UA_AddReferencesResponse UA_Client_addReferences(UA_Client *client, UA_AddReferencesRequest *request) {
     UA_AddReferencesResponse response;
-    synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
-                       &UA_TYPES[UA_TYPES_BROWSERESPONSE], client);
+    synchronousRequest(client, request, &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST],
+                       &response, &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]);
     return response;
 }
 
 UA_DeleteNodesResponse UA_Client_deleteNodes(UA_Client *client, UA_DeleteNodesRequest *request) {
     UA_DeleteNodesResponse response;
-    synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
-                       &UA_TYPES[UA_TYPES_BROWSERESPONSE], client);
+    synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETENODESREQUEST],
+                       &response, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]);
     return response;
 }
 
 UA_DeleteReferencesResponse UA_Client_deleteReferences(UA_Client *client, UA_DeleteReferencesRequest *request) {
     UA_DeleteReferencesResponse response;
-    synchronousRequest(request, &UA_TYPES[UA_TYPES_BROWSEREQUEST], &response,
-                       &UA_TYPES[UA_TYPES_BROWSERESPONSE], client);
-    return response;;
+    synchronousRequest(client, request, &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST],
+                       &response, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]);
+    return response;
 }

+ 60 - 117
src/server/ua_server_binary.c

@@ -90,6 +90,17 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     Service_OpenSecureChannel(server, connection, &r, &p);
     UA_OpenSecureChannelRequest_deleteMembers(&r);
 
+    UA_SecureChannel *channel = connection->channel;
+    if(!channel) {
+        connection->close(connection);
+        UA_OpenSecureChannelResponse_deleteMembers(&p);
+        UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
+        return;
+    }
+
+    /* send the response with an asymmetric security header */
+    seqHeader.sequenceNumber = channel->sequenceNumber;
+
     UA_SecureConversationMessageHeader respHeader;
     respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
     respHeader.messageHeader.messageSize = 0;
@@ -134,8 +145,10 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
 
 /* The request/response are casted to the header (first element of their struct) */
 static void invoke_service(UA_Server *server, UA_SecureChannel *channel,
-                           UA_RequestHeader *request, UA_ResponseHeader *response,
+                           UA_UInt32 requestId, UA_RequestHeader *request, const UA_DataType *responseType,
                            void (*service)(UA_Server*, UA_Session*, void*, void*)) {
+    UA_ResponseHeader *response = UA_alloca(responseType->memSize); // bigger than the response header only
+    UA_init(response, responseType);
     init_response_header(request, response);
     /* try to get the session from the securechannel first */
     UA_Session *session = UA_SecureChannel_getSession(channel, &request->authenticationToken);
@@ -145,55 +158,48 @@ static void invoke_service(UA_Server *server, UA_SecureChannel *channel,
         response->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
     else if(session->activated == UA_FALSE) {
         response->serviceResult = UA_STATUSCODE_BADSESSIONNOTACTIVATED;
-        /* the session is invalidated */
+        /* the session is invalidated FIXME: do this delayed*/
         UA_SessionManager_removeSession(&server->sessionManager, &request->authenticationToken);
-    }
-    else if(session->channel != channel)
+    } else if(session->channel != channel) {
         response->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
-    else {
-            UA_Session_updateLifetime(session);
-            service(server, session, request, response);
+    } else {
+        UA_Session_updateLifetime(session);
+        service(server, session, request, response);
     }
+    UA_SecureChannel_sendBinaryMessage(channel, requestId, response, responseType);
+    UA_deleteMembers(response, responseType);
 }
 
-#define INVOKE_SERVICE(TYPE) do {                                       \
-        UA_##TYPE##Request p;                                           \
-        UA_##TYPE##Response r;                                          \
-        if(UA_##TYPE##Request_decodeBinary(msg, pos, &p))               \
+#define INVOKE_SERVICE(REQUEST, RESPONSETYPE) do {                      \
+        UA_##REQUEST##Request p;                                        \
+        if(UA_##REQUEST##Request_decodeBinary(msg, pos, &p))            \
             return;                                                     \
-        UA_##TYPE##Response_init(&r);                                   \
-        invoke_service(server, clientChannel, &p.requestHeader,         \
-                       &r.responseHeader,                               \
-                       (void (*)(UA_Server*, UA_Session*, void*,void*))Service_##TYPE); \
-        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);                          \
+        invoke_service(server, clientChannel, sequenceHeader.requestId, \
+                       &p.requestHeader, &UA_TYPES[RESPONSETYPE],       \
+                       (void (*)(UA_Server*, UA_Session*, void*,void*))Service_##REQUEST); \
+        UA_##REQUEST##Request_deleteMembers(&p);                        \
 } while(0)
 
 static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) {
-    // 1) Read in the securechannel
+    /* Read in the securechannel */
     UA_UInt32 secureChannelId;
     UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
     if(retval != UA_STATUSCODE_GOOD)
         return;
 
     UA_SecureChannel *clientChannel = connection->channel;
-#ifdef EXTENSION_STATELESS
+    /* the anonymous channel is used e.g. to allow getEndpoints without a channel */
     UA_SecureChannel anonymousChannel;
     if(!clientChannel) {
         UA_SecureChannel_init(&anonymousChannel);
-        anonymousChannel.session = &anonymousSession;
+        anonymousChannel.connection = connection;
         clientChannel = &anonymousChannel;
-    }
+#ifdef EXTENSION_STATELESS
+        anonymousChannel.session = &anonymousSession;
 #endif
+    }
 
-    // 2) Read the security header
+    /* Read the security header */
     UA_UInt32 tokenId;
     UA_SequenceHeader sequenceHeader;
     retval = UA_UInt32_decodeBinary(msg, pos, &tokenId);
@@ -201,45 +207,18 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     if(retval != UA_STATUSCODE_GOOD)
         return;
 
-    //UA_SecureChannel_checkSequenceNumber(channel,sequenceHeader.sequenceNumber);
-    //UA_SecureChannel_checkRequestId(channel,sequenceHeader.requestId);
-    clientChannel->sequenceNumber = sequenceHeader.sequenceNumber;
-    clientChannel->requestId = sequenceHeader.requestId;
-
-    // 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;
+    /* Read the request type */
     UA_NodeId requestType;
-    if(UA_NodeId_decodeBinary(msg, pos, &requestType))
+    if(UA_NodeId_decodeBinary(msg, pos, &requestType) != UA_STATUSCODE_GOOD)
         return;
     if(requestType.identifierType != UA_NODEIDTYPE_NUMERIC) {
         UA_NodeId_deleteMembers(&requestType);
         return;
     }
 
-    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_GetEndpointsRequest p;
         UA_GetEndpointsResponse r;
         if(UA_GetEndpointsRequest_decodeBinary(msg, pos, &p))
             return;
@@ -247,12 +226,8 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_GetEndpoints(server, &p, &r);
         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_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r,
+                                           &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);
         UA_GetEndpointsResponse_deleteMembers(&r);
         break;
     }
@@ -266,12 +241,8 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_FindServers(server, &p, &r);
         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_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r,
+                                           &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]);
         UA_FindServersResponse_deleteMembers(&r);
         break;
     }
@@ -285,12 +256,8 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_CreateSession(server, clientChannel, &p, &r);
         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_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r,
+                                           &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]);
         UA_CreateSessionResponse_deleteMembers(&r);
         break;
     }
@@ -304,53 +271,48 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         init_response_header(&p.requestHeader, &r.responseHeader);
         Service_ActivateSession(server, clientChannel, &p, &r);
         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_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r,
+                                           &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]);
         UA_ActivateSessionResponse_deleteMembers(&r);
         break;
     }
 
     case UA_NS0ID_CLOSESESSIONREQUEST:
-        INVOKE_SERVICE(CloseSession);
+        INVOKE_SERVICE(CloseSession, UA_TYPES_CLOSESESSIONRESPONSE);
         break;
     case UA_NS0ID_READREQUEST:
-        INVOKE_SERVICE(Read);
+        INVOKE_SERVICE(Read, UA_TYPES_READRESPONSE);
         break;
     case UA_NS0ID_WRITEREQUEST:
-        INVOKE_SERVICE(Write);
+        INVOKE_SERVICE(Write, UA_TYPES_WRITERESPONSE);
         break;
     case UA_NS0ID_BROWSEREQUEST:
-        INVOKE_SERVICE(Browse);
+        INVOKE_SERVICE(Browse, UA_TYPES_BROWSERESPONSE);
         break;
     case UA_NS0ID_BROWSENEXTREQUEST:
-        INVOKE_SERVICE(BrowseNext);
+        INVOKE_SERVICE(BrowseNext, UA_TYPES_BROWSENEXTRESPONSE);
         break;
     case UA_NS0ID_ADDREFERENCESREQUEST:
-        INVOKE_SERVICE(AddReferences);
+        INVOKE_SERVICE(AddReferences, UA_TYPES_ADDREFERENCESRESPONSE);
         break;
     case UA_NS0ID_REGISTERNODESREQUEST:
-        INVOKE_SERVICE(RegisterNodes);
+        INVOKE_SERVICE(RegisterNodes, UA_TYPES_REGISTERNODESRESPONSE);
         break;
     case UA_NS0ID_UNREGISTERNODESREQUEST:
-        INVOKE_SERVICE(UnregisterNodes);
+        INVOKE_SERVICE(UnregisterNodes, UA_TYPES_UNREGISTERNODESRESPONSE);
         break;
     case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
-        INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
+        INVOKE_SERVICE(TranslateBrowsePathsToNodeIds, UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE);
         break;
-
     default: {
-        if(requestType.namespaceIndex == 0 && requestType.identifier.numeric==787){
+        if(requestType.namespaceIndex == 0 && requestType.identifier.numeric==787) {
             UA_LOG_INFO(server->logger, UA_LOGCATEGORY_COMMUNICATION,
                         "Client requested a subscription that are not supported, the message will be skipped");
-        }else{
+        } else {
             UA_LOG_INFO(server->logger, UA_LOGCATEGORY_COMMUNICATION, "Unknown request: NodeId(ns=%d, i=%d)",
                         requestType.namespaceIndex, requestType.identifier.numeric);
         }
-        UA_RequestHeader  p;
+        UA_RequestHeader p;
         UA_ResponseHeader r;
         if(UA_RequestHeader_decodeBinary(msg, pos, &p) != UA_STATUSCODE_GOOD)
             return;
@@ -362,30 +324,11 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
             r.serviceResult = retval;
 #endif
         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);
-        response_nodeid = UA_NODEID_NUMERIC(0, UA_NS0ID_RESPONSEHEADER + UA_ENCODINGOFFSET_BINARY);
+        UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId,
+            &r, &UA_TYPES[UA_TYPES_RESPONSEHEADER]);
         break;
     }
     }
-
-    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
-
-    // 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) {

+ 57 - 20
src/ua_securechannel.c

@@ -2,6 +2,7 @@
 #include "ua_securechannel.h"
 #include "ua_session.h"
 #include "ua_statuscodes.h"
+#include "ua_types_encoding_binary.h"
 
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
     UA_MessageSecurityMode_init(&channel->securityMode);
@@ -10,7 +11,6 @@ void UA_SecureChannel_init(UA_SecureChannel *channel) {
     UA_AsymmetricAlgorithmSecurityHeader_init(&channel->serverAsymAlgSettings);
     UA_ByteString_init(&channel->clientNonce);
     UA_ByteString_init(&channel->serverNonce);
-    channel->requestId = 0;
     channel->sequenceNumber = 0;
     channel->connection = UA_NULL;
     LIST_INIT(&channel->sessions);
@@ -43,22 +43,6 @@ UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce) {
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UInt32 requestId) {
-    //TODO review checking of request id
-    if(channel->requestId+1 != requestId)
-        return UA_STATUSCODE_BADINTERNALERROR;
-    channel->requestId++;
-    return UA_STATUSCODE_GOOD;
-}
-
-UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) {
-    //TODO review checking of sequence
-    if(channel->sequenceNumber+1  != sequenceNumber)
-        return UA_STATUSCODE_BADINTERNALERROR;
-    channel->sequenceNumber++;
-    return UA_STATUSCODE_GOOD;
-}
-
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session) {
     struct SessionEntry *se = UA_malloc(sizeof(struct SessionEntry));
     if(!se)
@@ -98,8 +82,61 @@ UA_Session * UA_SecureChannel_getSession(UA_SecureChannel *channel, UA_NodeId *t
         if(UA_NodeId_equal(&se->session->authenticationToken, token))
             break;
     }
-    if(se)
-        return se->session;
-    else
+    if(!se)
         return UA_NULL;
+    return se->session;
+}
+
+UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
+                                                  const void *content,
+                                                  const UA_DataType *contentType) {
+    UA_Connection *connection = channel->connection;
+    if(!connection)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    UA_NodeId typeId = contentType->typeId;
+    if(typeId.identifierType != UA_NODEIDTYPE_NUMERIC)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    typeId.identifier.numeric += UA_ENCODINGOFFSET_BINARY;
+
+    UA_SecureConversationMessageHeader respHeader;
+    respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
+    respHeader.messageHeader.messageSize = 0;
+    respHeader.secureChannelId = channel->securityToken.channelId;
+
+    UA_SymmetricAlgorithmSecurityHeader symSecHeader;
+    symSecHeader.tokenId = channel->securityToken.tokenId;
+
+    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)
+        return retval;
+
+    /* do this only now, so the sequence number does not increase if sth fails */
+#ifndef UA_MULTITHREADING
+    seqHeader.sequenceNumber = ++channel->sequenceNumber;
+#else
+    seqHeader.sequenceNumber = uatomic_add_return(&channel->sequenceNumber, 1);
+#endif
+
+    size_t 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);
+    
+    connection->write(connection, &message);
+    connection->releaseBuffer(connection, &message);
+    return UA_STATUSCODE_GOOD;
 }

+ 3 - 3
src/ua_securechannel.h

@@ -27,7 +27,6 @@ struct UA_SecureChannel {
     UA_AsymmetricAlgorithmSecurityHeader serverAsymAlgSettings;
     UA_ByteString  clientNonce;
     UA_ByteString  serverNonce;
-    UA_UInt32      requestId;
     UA_UInt32      sequenceNumber;
     UA_Connection *connection;
     LIST_HEAD(session_pointerlist, SessionEntry) sessions;
@@ -37,13 +36,14 @@ void UA_SecureChannel_init(UA_SecureChannel *channel);
 void UA_SecureChannel_deleteMembersCleanup(UA_SecureChannel *channel);
 
 UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce);
-UA_StatusCode UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UInt32 requestId);
-UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber);
 
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session);
 void UA_SecureChannel_detachSession(UA_SecureChannel *channel, UA_Session *session);
 UA_Session * UA_SecureChannel_getSession(UA_SecureChannel *channel, UA_NodeId *token);
 
+UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
+                                                  const void *content, const UA_DataType *contentType);
+
 /** @} */
 
 #endif /* UA_SECURECHANNEL_H_ */