123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- #include "ua_server.h"
- #include "ua_services.h"
- #include "ua_statuscodes.h"
- #include "ua_namespace_0.h"
- #include "ua_securechannel_manager.h"
- #include "ua_session_manager.h"
- #include "ua_util.h"
- static UA_Int32 UA_ByteStringArray_deleteMembers(UA_ByteStringArray *stringarray) {
- if(!stringarray)
- return UA_ERROR;
- for(UA_UInt32 i = 0;i < stringarray->stringsSize;i++)
- UA_String_deleteMembers(&stringarray->strings[i]);
- return UA_SUCCESS;
- }
- static void processHello(UA_Connection *connection, const UA_ByteString *msg,
- UA_UInt32 *pos) {
- UA_TcpHelloMessage helloMessage;
- if(UA_TcpHelloMessage_decodeBinary(msg, pos, &helloMessage) != UA_SUCCESS) {
- connection->close(connection->callbackHandle);
- return;
- }
- connection->remoteConf.maxChunkCount = helloMessage.maxChunkCount;
- connection->remoteConf.maxMessageSize = helloMessage.maxMessageSize;
- connection->remoteConf.protocolVersion = helloMessage.protocolVersion;
- connection->remoteConf.recvBufferSize = helloMessage.receiveBufferSize;
- connection->remoteConf.sendBufferSize = helloMessage.sendBufferSize;
- connection->state = UA_CONNECTION_ESTABLISHED;
- // build acknowledge response
- UA_TcpAcknowledgeMessage ackMessage;
- ackMessage.protocolVersion = connection->localConf.protocolVersion;
- ackMessage.receiveBufferSize = connection->localConf.recvBufferSize;
- ackMessage.sendBufferSize = connection->localConf.sendBufferSize;
- ackMessage.maxMessageSize = connection->localConf.maxMessageSize;
- ackMessage.maxChunkCount = connection->localConf.maxChunkCount;
- UA_TcpMessageHeader ackHeader;
- ackHeader.messageType = UA_MESSAGETYPE_ACK;
- ackHeader.isFinal = 'F';
- ackHeader.messageSize = UA_TcpAcknowledgeMessage_calcSizeBinary(&ackMessage) +
- UA_TcpMessageHeader_calcSizeBinary(&ackHeader);
- UA_ByteString ack_msg;
- UA_UInt32 tmpPos = 0;
- UA_ByteString_newMembers(&ack_msg, ackHeader.messageSize);
- 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->callbackHandle, answer_buf); // the string is freed internall in the (asynchronous) write
- UA_TcpHelloMessage_deleteMembers(&helloMessage);
- }
- static void processOpen(UA_Connection *connection, UA_Server *server,
- const UA_ByteString *msg, UA_UInt32 *pos) {
- if(connection->state != UA_CONNECTION_ESTABLISHED) {
- // was hello exchanged before?
- if(connection->state == UA_CONNECTION_OPENING)
- connection->close(connection->callbackHandle);
- return;
- }
- UA_UInt32 secureChannelId;
- UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
- UA_AsymmetricAlgorithmSecurityHeader asymHeader;
- UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(msg, pos, &asymHeader);
- UA_SequenceHeader seqHeader;
- UA_SequenceHeader_decodeBinary(msg, pos, &seqHeader);
- UA_ExpandedNodeId requestType;
- UA_ExpandedNodeId_decodeBinary(msg, pos, &requestType);
- if(requestType.nodeId.identifier.numeric != 446) {
- // todo: handle error
- }
- UA_OpenSecureChannelRequest r;
- UA_OpenSecureChannelRequest_decodeBinary(msg, pos, &r);
- // perform request
- UA_OpenSecureChannelResponse p;
- UA_OpenSecureChannelResponse_init(&p);
- Service_OpenSecureChannel(server, connection, &r, &p);
- // response
- UA_TcpMessageHeader respHeader;
- respHeader.messageType = UA_MESSAGETYPE_OPN;
- respHeader.isFinal = 'F';
- respHeader.messageSize = 8+4; //header + securechannelid
- UA_ExpandedNodeId responseType;
- NS0EXPANDEDNODEID(responseType, 449);
- respHeader.messageSize += UA_AsymmetricAlgorithmSecurityHeader_calcSizeBinary(&asymHeader);
- respHeader.messageSize += UA_SequenceHeader_calcSizeBinary(&seqHeader);
- respHeader.messageSize += UA_ExpandedNodeId_calcSizeBinary(&responseType);
- respHeader.messageSize += UA_OpenSecureChannelResponse_calcSizeBinary(&p);
- UA_ByteString resp_msg;
- UA_UInt32 tmpPos = 0;
- UA_ByteString_newMembers(&resp_msg, respHeader.messageSize);
- UA_TcpMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
- UA_UInt32_encodeBinary(&p.securityToken.channelId, &resp_msg, &tmpPos);
- UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back
- UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos); // just mirror back
- UA_ExpandedNodeId_encodeBinary(&responseType, &resp_msg, &tmpPos);
- UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos);
- UA_OpenSecureChannelRequest_deleteMembers(&r);
- UA_OpenSecureChannelResponse_deleteMembers(&p);
- UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
-
- UA_ByteStringArray answer_buf = { .stringsSize = 1, .strings = &resp_msg };
- connection->write(connection->callbackHandle, answer_buf);
- }
- static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r) {
- r->requestHandle = p->requestHandle;
- r->serviceResult = UA_STATUSCODE_GOOD;
- r->stringTableSize = 0;
- r->timestamp = UA_DateTime_now();
- }
- #define CHECK_PROCESS(CODE, CLEANUP) \
- do { if(CODE != UA_SUCCESS) { \
- CLEANUP; \
- return; \
- } } while(0)
- #define INVOKE_SERVICE(TYPE) do { \
- UA_##TYPE##Request p; \
- UA_##TYPE##Response r; \
- CHECK_PROCESS(UA_##TYPE##Request_decodeBinary(msg, pos, &p),; ); \
- UA_##TYPE##Response_init(&r); \
- init_response_header(&p.requestHeader, &r.responseHeader); \
- DBG_VERBOSE(printf("Invoke Service: %s\n", # TYPE)); \
- Service_##TYPE(server, channel->session, &p, &r); \
- DBG_VERBOSE(printf("Finished Service: %s\n", # TYPE)); \
- UA_ByteString_newMembers(message, UA_##TYPE##Response_calcSizeBinary(&r)); \
- UA_##TYPE##Response_encodeBinary(&r, message, &sendOffset); \
- UA_##TYPE##Request_deleteMembers(&p); \
- UA_##TYPE##Response_deleteMembers(&r); \
- responseType = requestType.nodeId.identifier.numeric + 3; \
- } while(0)
- static void processMessage(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, UA_UInt32 *pos) {
- // 1) Read in the securechannel
- UA_UInt32 secureChannelId;
- UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
- UA_SecureChannel *channel;
- UA_SecureChannelManager_get(server->secureChannelManager, secureChannelId, &channel);
- // 2) Read the security header
- UA_UInt32 tokenId;
- UA_UInt32_decodeBinary(msg, pos, &tokenId);
- UA_SequenceHeader sequenceHeader;
- CHECK_PROCESS(UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader),; );
- channel->sequenceNumber = sequenceHeader.sequenceNumber;
- channel->requestId = sequenceHeader.requestId;
- // todo
- //UA_SecureChannel_checkSequenceNumber(channel,sequenceHeader.sequenceNumber);
- //UA_SecureChannel_checkRequestId(channel,sequenceHeader.requestId);
- // 3) Read the nodeid of the request
- UA_ExpandedNodeId requestType;
- CHECK_PROCESS(UA_ExpandedNodeId_decodeBinary(msg, pos, &requestType),; );
- if(requestType.nodeId.identifierType != UA_NODEIDTYPE_NUMERIC) {
- UA_ExpandedNodeId_deleteMembers(&requestType); // if the nodeidtype is numeric, we do not have to free anything
- 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];
- UA_UInt32 sendOffset = 0;
- //subtract UA_ENCODINGOFFSET_BINARY for binary encoding
- switch(requestType.nodeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY) {
- case UA_GETENDPOINTSREQUEST_NS0: {
- UA_GetEndpointsRequest p;
- UA_GetEndpointsResponse r;
- CHECK_PROCESS(UA_GetEndpointsRequest_decodeBinary(msg, pos, &p),; );
- UA_GetEndpointsResponse_init(&r);
- init_response_header(&p.requestHeader, &r.responseHeader);
- Service_GetEndpoints(server, &p, &r);
- UA_ByteString_newMembers(message, UA_GetEndpointsResponse_calcSizeBinary(&r));
- UA_GetEndpointsResponse_encodeBinary(&r, message, &sendOffset);
- UA_GetEndpointsRequest_deleteMembers(&p);
- UA_GetEndpointsResponse_deleteMembers(&r);
- responseType = requestType.nodeId.identifier.numeric + 3;
- break;
- }
- case UA_CREATESESSIONREQUEST_NS0: {
- UA_CreateSessionRequest p;
- UA_CreateSessionResponse r;
- CHECK_PROCESS(UA_CreateSessionRequest_decodeBinary(msg, pos, &p),; );
- UA_CreateSessionResponse_init(&r);
- init_response_header(&p.requestHeader, &r.responseHeader);
- Service_CreateSession(server, channel, &p, &r);
- UA_ByteString_newMembers(message, UA_CreateSessionResponse_calcSizeBinary(&r));
- UA_CreateSessionResponse_encodeBinary(&r, message, &sendOffset);
- UA_CreateSessionRequest_deleteMembers(&p);
- UA_CreateSessionResponse_deleteMembers(&r);
- responseType = requestType.nodeId.identifier.numeric + 3;
- break;
- }
- case UA_ACTIVATESESSIONREQUEST_NS0: {
- UA_ActivateSessionRequest p;
- UA_ActivateSessionResponse r;
- CHECK_PROCESS(UA_ActivateSessionRequest_decodeBinary(msg, pos, &p),; );
- UA_ActivateSessionResponse_init(&r);
- init_response_header(&p.requestHeader, &r.responseHeader);
- Service_ActivateSession(server, channel, &p, &r);
- UA_ByteString_newMembers(message, UA_ActivateSessionResponse_calcSizeBinary(&r));
- UA_ActivateSessionResponse_encodeBinary(&r, message, &sendOffset);
- UA_ActivateSessionRequest_deleteMembers(&p);
- UA_ActivateSessionResponse_deleteMembers(&r);
- responseType = requestType.nodeId.identifier.numeric + 3;
- }
- break;
- case UA_CLOSESESSIONREQUEST_NS0: {
- UA_CloseSessionRequest p;
- UA_CloseSessionResponse r;
- CHECK_PROCESS(UA_CloseSessionRequest_decodeBinary(msg, pos, &p),; );
- UA_CloseSessionResponse_init(&r);
- init_response_header(&p.requestHeader, &r.responseHeader);
- Service_CloseSession(server, &p, &r);
- UA_ByteString_newMembers(message, UA_CloseSessionResponse_calcSizeBinary(&r));
- UA_CloseSessionResponse_encodeBinary(&r, message, &sendOffset);
- UA_CloseSessionRequest_deleteMembers(&p);
- UA_CloseSessionResponse_deleteMembers(&r);
- responseType = requestType.nodeId.identifier.numeric + 3;
- }
- break;
- case UA_READREQUEST_NS0:
- INVOKE_SERVICE(Read);
- break;
- case UA_WRITEREQUEST_NS0:
- INVOKE_SERVICE(Write);
- break;
- case UA_BROWSEREQUEST_NS0:
- INVOKE_SERVICE(Browse);
- break;
- /* case UA_CREATESUBSCRIPTIONREQUEST_NS0: */
- /* INVOKE_SERVICE(CreateSubscription); */
- /* break; */
- case UA_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_NS0:
- INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
- break;
- /* case UA_PUBLISHREQUEST_NS0: */
- /* INVOKE_SERVICE(Publish); */
- /* break; */
- /* case UA_CREATEMONITOREDITEMSREQUEST_NS0: */
- /* INVOKE_SERVICE(CreateMonitoredItems); */
- /* break; */
- /* case UA_SETPUBLISHINGMODEREQUEST_NS0: */
- /* INVOKE_SERVICE(SetPublishingMode); */
- /* break; */
- default: {
- printf("SL_processMessage - unknown request, namespace=%d, request=%d\n",
- requestType.nodeId.namespaceIndex, requestType.nodeId.identifier.numeric);
- UA_RequestHeader p;
- UA_ResponseHeader r;
- CHECK_PROCESS(UA_RequestHeader_decodeBinary(msg, pos, &p),; );
- UA_ResponseHeader_init(&r);
- r.requestHandle = p.requestHandle;
- r.serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
- UA_ByteString_newMembers(message, UA_ResponseHeader_calcSizeBinary(&r));
- UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
- UA_RequestHeader_deleteMembers(&p);
- UA_ResponseHeader_deleteMembers(&r);
- responseType = UA_RESPONSEHEADER_NS0 + 2;
- }
- break;
- }
- // 5) Build the header
- UA_NodeId response_nodeid = { .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
- .identifier.numeric = responseType }; // add 2 for binary encoding
- UA_ByteString_newMembers(header,
- 8 + 16 + // message header + 4*32bit secure channel information
- UA_NodeId_calcSizeBinary(&response_nodeid));
- // header
- UA_TcpMessageHeader respHeader;
- respHeader.messageType = UA_MESSAGETYPE_MSG;
- respHeader.isFinal = 'F';
- respHeader.messageSize = header->length + message->length;
- UA_UInt32 rpos = 0;
- UA_TcpMessageHeader_encodeBinary(&respHeader, header, &rpos);
- UA_UInt32_encodeBinary(&channel->securityToken.channelId, header, &rpos); // channel id
- UA_UInt32_encodeBinary(&channel->securityToken.tokenId, header, &rpos); // algorithm security header
- UA_UInt32_encodeBinary(&channel->sequenceNumber, header, &rpos); // encode sequence header
- UA_UInt32_encodeBinary(&channel->requestId, header, &rpos);
- UA_NodeId_encodeBinary(&response_nodeid, header, &rpos); // add payload type
- // sign data
- // encrypt data
- // 6) Send it over the wire.
- UA_ByteStringArray responseBufArray;
- responseBufArray.strings = responseBufs; // the content is deleted in the write function (asynchronous)
- responseBufArray.stringsSize = 2;
- connection->write(connection->callbackHandle, responseBufArray);
- }
- static void processClose(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, UA_UInt32 *pos) {
- // just read in the sequenceheader
- UA_UInt32 secureChannelId;
- UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
- //the two last parameter is ignored since no answer is needed
- Service_CloseSecureChannel(server, secureChannelId);
- }
- UA_Int32 UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg) {
- UA_Int32 retval = UA_SUCCESS;
- UA_UInt32 pos = 0;
- UA_TcpMessageHeader tcpMessageHeader;
- // todo: test how far pos advanced must be equal to what is said in the messageheader
- do {
- retval = UA_TcpMessageHeader_decodeBinary(msg, &pos, &tcpMessageHeader);
- UA_UInt32 targetpos = pos - 8 + tcpMessageHeader.messageSize;
- if(retval == UA_SUCCESS) {
- // none of the process-functions returns an error its all contained inside.
- switch(tcpMessageHeader.messageType) {
- case UA_MESSAGETYPE_HEL:
- processHello(connection, msg, &pos);
- break;
- case UA_MESSAGETYPE_OPN:
- processOpen(connection, server, msg, &pos);
- break;
- case UA_MESSAGETYPE_MSG:
- //no break
- // if this fails, the connection is closed (no break on the case)
- if(connection->state == UA_CONNECTION_ESTABLISHED &&
- connection->channel != UA_NULL) {
- processMessage(connection, server, msg, &pos);
- break;
- }
- case UA_MESSAGETYPE_CLO:
- connection->state = UA_CONNECTION_CLOSING;
- processClose(connection, server, msg, &pos);
- connection->close(connection->callbackHandle);
- return retval;
- }
- UA_TcpMessageHeader_deleteMembers(&tcpMessageHeader);
- } else {
- printf("TL_Process - ERROR: decoding of header failed \n");
- connection->state = UA_CONNECTION_CLOSING;
- //processClose(connection, server, msg, &pos);
- connection->close(connection->callbackHandle);
- }
- // todo: more than one message at once..
- if(pos != targetpos) {
- printf("The message size was not as announced or an error occurred while processing, skipping to the end of the message.\n");
- pos = targetpos;
- }
- } while(msg->length > (UA_Int32)pos);
- return retval;
- }
|