/** * Decode the request message type from the given byte string and * set the global requestServiceName variable to the name of the request. * E.g. `GetEndpointsRequest` */ static UA_StatusCode UA_debug_dumpSetServiceName(const UA_ByteString *msg, char serviceNameTarget[100]) { /* At 0, the nodeid starts... */ size_t offset = 0; /* Decode the nodeid */ UA_NodeId requestTypeId; UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &requestTypeId); if(retval != UA_STATUSCODE_GOOD) return retval; if(requestTypeId.identifierType != UA_NODEIDTYPE_NUMERIC || requestTypeId.namespaceIndex != 0) { snprintf(serviceNameTarget, 100, "invalid_request_id"); return UA_STATUSCODE_BADUNEXPECTEDERROR; } const UA_DataType *requestType = NULL; for (size_t i=0; i<UA_TYPES_COUNT; i++) { if (UA_TYPES[i].binaryEncodingId == requestTypeId.identifier.numeric) { requestType = &UA_TYPES[i]; break; } } if (requestType == NULL) { snprintf(serviceNameTarget, 100, "invalid_request_no_type"); return UA_STATUSCODE_BADUNEXPECTEDERROR; } snprintf(serviceNameTarget, 100, "_%s", requestType->typeName); return UA_STATUSCODE_GOOD; }
void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *requestType, void *response, const UA_DataType *responseType) { /* Requests always begin witih a RequestHeader, therefore we can cast. */ UA_RequestHeader *request = (void*)(uintptr_t)r; UA_StatusCode retval = UA_STATUSCODE_GOOD; UA_init(response, responseType); UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response; /* make sure we have a valid session */ retval = UA_Client_manuallyRenewSecureChannel(client); if(retval != UA_STATUSCODE_GOOD) { respHeader->serviceResult = retval; client->state = UA_CLIENTSTATE_ERRORED; return; } /* handling request parameters */ UA_NodeId_copy(&client->authenticationToken, &request->authenticationToken); request->timestamp = UA_DateTime_now(); request->requestHandle = ++client->requestHandle; /* Send the request */ UA_UInt32 requestId = ++client->requestId; UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT, "Sending a request of type %i", requestType->typeId.identifier.numeric); retval = UA_SecureChannel_sendBinaryMessage(&client->channel, requestId, request, requestType); if(retval) { if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE; else respHeader->serviceResult = retval; client->state = UA_CLIENTSTATE_ERRORED; return; } /* Retrieve the response */ // Todo: push this into the generic securechannel implementation for client and server UA_ByteString reply; UA_ByteString_init(&reply); do { retval = client->connection.recv(&client->connection, &reply, client->config.timeout); if(retval != UA_STATUSCODE_GOOD) { respHeader->serviceResult = retval; client->state = UA_CLIENTSTATE_ERRORED; return; } } while(!reply.data); 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(retval != UA_STATUSCODE_GOOD) { goto finish; } /* Todo: we need to demux responses since a publish responses may come at any time */ if(!UA_NodeId_equal(&responseId, &expectedNodeId) || seqHeader.requestId != requestId) { if(responseId.identifier.numeric != UA_NS0ID_SERVICEFAULT + UA_ENCODINGOFFSET_BINARY) { UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "Reply answers the wrong request. Expected ns=%i,i=%i. But retrieved ns=%i,i=%i", expectedNodeId.namespaceIndex, expectedNodeId.identifier.numeric, responseId.namespaceIndex, responseId.identifier.numeric); respHeader->serviceResult = UA_STATUSCODE_BADINTERNALERROR; } else retval = UA_decodeBinary(&reply, &offset, respHeader, &UA_TYPES[UA_TYPES_SERVICEFAULT]); goto finish; } retval = UA_decodeBinary(&reply, &offset, response, responseType); if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) retval = UA_STATUSCODE_BADRESPONSETOOLARGE; finish: UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader); UA_ByteString_deleteMembers(&reply); if(retval != UA_STATUSCODE_GOOD){ UA_LOG_INFO(client->logger, UA_LOGCATEGORY_CLIENT, "Error receiving the response"); client->state = UA_CLIENTSTATE_ERRORED; respHeader->serviceResult = retval; } UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT, "Received a response of type %i", responseId.identifier.numeric); }
static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew) { /* Check if sc is still valid */ if(renew && client->scExpiresAt - UA_DateTime_now() > client->config.timeToRenewSecureChannel * 10000) return UA_STATUSCODE_GOOD; UA_SecureConversationMessageHeader messageHeader; messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF; messageHeader.secureChannelId = 0; UA_SequenceHeader seqHeader; seqHeader.sequenceNumber = ++client->channel.sequenceNumber; seqHeader.requestId = ++client->requestId; UA_AsymmetricAlgorithmSecurityHeader asymHeader; UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); asymHeader.securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None"); /* id of opensecurechannelrequest */ UA_NodeId requestType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY); UA_OpenSecureChannelRequest opnSecRq; UA_OpenSecureChannelRequest_init(&opnSecRq); opnSecRq.requestHeader.timestamp = UA_DateTime_now(); opnSecRq.requestHeader.authenticationToken = client->authenticationToken; opnSecRq.requestedLifetime = client->config.secureChannelLifeTime; if(renew) { opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW; UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to renew the SecureChannel"); } else { opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE; UA_ByteString_init(&client->channel.clientNonce); UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce); opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE; UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to open a SecureChannel"); } UA_ByteString message; UA_Connection *c = &client->connection; UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message); if(retval != UA_STATUSCODE_GOOD) { UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq); return retval; } size_t offset = 12; retval = UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &message, &offset); retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset); retval |= UA_NodeId_encodeBinary(&requestType, &message, &offset); retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset); messageHeader.messageHeader.messageSize = offset; offset = 0; retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &message, &offset); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq); if(retval != UA_STATUSCODE_GOOD) { client->connection.releaseSendBuffer(&client->connection, &message); return retval; } message.length = messageHeader.messageHeader.messageSize; retval = client->connection.send(&client->connection, &message); if(retval != UA_STATUSCODE_GOOD) return retval; UA_ByteString reply; UA_ByteString_init(&reply); do { retval = client->connection.recv(&client->connection, &reply, client->config.timeout); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Receiving OpenSecureChannelResponse failed"); return retval; } } while(!reply.data); offset = 0; UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &messageHeader); UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &asymHeader); UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader); UA_NodeId_decodeBinary(&reply, &offset, &requestType); UA_NodeId expectedRequest = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE + UA_ENCODINGOFFSET_BINARY); if(!UA_NodeId_equal(&requestType, &expectedRequest)) { UA_ByteString_deleteMembers(&reply); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_NodeId_deleteMembers(&requestType); UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT, "Reply answers the wrong request. Expected OpenSecureChannelResponse."); return UA_STATUSCODE_BADINTERNALERROR; } UA_OpenSecureChannelResponse response; UA_OpenSecureChannelResponse_init(&response); retval = UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Decoding OpenSecureChannelResponse failed"); UA_ByteString_deleteMembers(&reply); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_OpenSecureChannelResponse_init(&response); response.responseHeader.serviceResult = retval; return retval; } client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000; UA_ByteString_deleteMembers(&reply); retval = response.responseHeader.serviceResult; if(retval != UA_STATUSCODE_GOOD) UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel could not be opened / renewed"); else if(!renew) { UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel.securityToken); /* if the handshake is repeated, replace the old nonce */ UA_ByteString_deleteMembers(&client->channel.serverNonce); UA_ByteString_copy(&response.serverNonce, &client->channel.serverNonce); UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel opened"); } else UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel renewed"); UA_OpenSecureChannelResponse_deleteMembers(&response); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); return retval; }
static void processDecodedOPNResponseAsync(void *application, UA_SecureChannel *channel, UA_MessageType messageType, UA_UInt32 requestId, const UA_ByteString *message) { /* Does the request id match? */ UA_Client *client = (UA_Client*)application; if(requestId != client->requestId) { UA_Client_disconnect(client); return; } /* Is the content of the expected type? */ size_t offset = 0; UA_NodeId responseId; UA_NodeId expectedId = UA_NODEID_NUMERIC( 0, UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE].binaryEncodingId); UA_StatusCode retval = UA_NodeId_decodeBinary(message, &offset, &responseId); if(retval != UA_STATUSCODE_GOOD) { UA_Client_disconnect(client); return; } if(!UA_NodeId_equal(&responseId, &expectedId)) { UA_NodeId_deleteMembers(&responseId); UA_Client_disconnect(client); return; } UA_NodeId_deleteMembers (&responseId); /* Decode the response */ UA_OpenSecureChannelResponse response; retval = UA_OpenSecureChannelResponse_decodeBinary(message, &offset, &response); if(retval != UA_STATUSCODE_GOOD) { UA_Client_disconnect(client); return; } /* Response.securityToken.revisedLifetime is UInt32 we need to cast it to * DateTime=Int64 we take 75% of lifetime to start renewing as described in * standard */ client->nextChannelRenewal = UA_DateTime_nowMonotonic() + (UA_DateTime) (response.securityToken.revisedLifetime * (UA_Double) UA_DATETIME_MSEC * 0.75); /* Replace the token and nonce */ UA_ChannelSecurityToken_deleteMembers(&client->channel.securityToken); UA_ByteString_deleteMembers(&client->channel.remoteNonce); client->channel.securityToken = response.securityToken; client->channel.remoteNonce = response.serverNonce; UA_ResponseHeader_deleteMembers(&response.responseHeader); /* the other members were moved */ if(client->channel.state == UA_SECURECHANNELSTATE_OPEN) UA_LOG_DEBUG(&client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel renewed"); else UA_LOG_DEBUG(&client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel opened"); client->channel.state = UA_SECURECHANNELSTATE_OPEN; if(client->state < UA_CLIENTSTATE_SECURECHANNEL) setClientState(client, UA_CLIENTSTATE_SECURECHANNEL); }
static void processMSG(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId, const UA_ByteString *msg) { /* At 0, the nodeid starts... */ size_t ppos = 0; size_t *offset = &ppos; /* Decode the nodeid */ UA_NodeId requestTypeId; UA_StatusCode retval = UA_NodeId_decodeBinary(msg, offset, &requestTypeId); if(retval != UA_STATUSCODE_GOOD) return; if(requestTypeId.identifierType != UA_NODEIDTYPE_NUMERIC) UA_NodeId_deleteMembers(&requestTypeId); /* leads to badserviceunsupported */ /* Store the start-position of the request */ size_t requestPos = *offset; /* Get the service pointers */ UA_Service service = NULL; const UA_DataType *requestType = NULL; const UA_DataType *responseType = NULL; UA_Boolean sessionRequired = true; getServicePointers(requestTypeId.identifier.numeric, &requestType, &responseType, &service, &sessionRequired); if(!requestType) { if(requestTypeId.identifier.numeric == 787) { UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Client requested a subscription, " \ "but those are not enabled in the build"); } else { UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Unknown request %i", requestTypeId.identifier.numeric); } sendError(channel, msg, requestPos, &UA_TYPES[UA_TYPES_SERVICEFAULT], requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED); return; } UA_assert(responseType); #ifdef UA_ENABLE_NONSTANDARD_STATELESS /* Stateless extension: Sessions are optional */ sessionRequired = false; #endif /* Decode the request */ void *request = UA_alloca(requestType->memSize); UA_RequestHeader *requestHeader = (UA_RequestHeader*)request; retval = UA_decodeBinary(msg, offset, request, requestType); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Could not decode the request"); sendError(channel, msg, requestPos, responseType, requestId, retval); return; } /* Prepare the respone */ void *response = UA_alloca(responseType->memSize); UA_init(response, responseType); UA_Session *session = NULL; /* must be initialized before goto send_response */ /* CreateSession doesn't need a session */ if(requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]) { Service_CreateSession(server, channel, request, response); goto send_response; } /* Find the matching session */ session = UA_SecureChannel_getSession(channel, &requestHeader->authenticationToken); if(!session) session = UA_SessionManager_getSession(&server->sessionManager, &requestHeader->authenticationToken); if(requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST]) { if(!session) { UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Trying to activate a session that is " \ "not known in the server"); sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSESSIONIDINVALID); UA_deleteMembers(request, requestType); return; } Service_ActivateSession(server, channel, session, request, response); goto send_response; } /* Set an anonymous, inactive session for services that need no session */ UA_Session anonymousSession; if(!session) { if(sessionRequired) { UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Service request %i without a valid session", requestType->binaryEncodingId); sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSESSIONIDINVALID); UA_deleteMembers(request, requestType); return; } UA_Session_init(&anonymousSession); anonymousSession.sessionId = UA_NODEID_GUID(0, UA_GUID_NULL); anonymousSession.channel = channel; session = &anonymousSession; } /* Trying to use a non-activated session? */ if(sessionRequired && !session->activated) { UA_LOG_INFO_SESSION(server->config.logger, session, "Calling service %i on a non-activated session", requestType->binaryEncodingId); sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED); UA_SessionManager_removeSession(&server->sessionManager, &session->authenticationToken); UA_deleteMembers(request, requestType); return; } /* The session is bound to another channel */ if(session->channel != channel) { UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Client tries to use an obsolete securechannel"); sendError(channel, msg, requestPos, responseType, requestId, UA_STATUSCODE_BADSECURECHANNELIDINVALID); UA_deleteMembers(request, requestType); return; } /* Update the session lifetime */ UA_Session_updateLifetime(session); #ifdef UA_ENABLE_SUBSCRIPTIONS /* The publish request is not answered immediately */ if(requestType == &UA_TYPES[UA_TYPES_PUBLISHREQUEST]) { Service_Publish(server, session, request, requestId); UA_deleteMembers(request, requestType); return; } #endif /* Call the service */ UA_assert(service); /* For all services besides publish, the service pointer is non-NULL*/ service(server, session, request, response); send_response: /* Send the response */ ((UA_ResponseHeader*)response)->requestHandle = requestHeader->requestHandle; ((UA_ResponseHeader*)response)->timestamp = UA_DateTime_now(); retval = UA_SecureChannel_sendBinaryMessage(channel, requestId, response, responseType); if(retval != UA_STATUSCODE_GOOD) UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Could not send the message over " "the SecureChannel with error code 0x%08x", retval); /* Clean up */ UA_deleteMembers(request, requestType); UA_deleteMembers(response, responseType); }
/* OPN -> Open up/renew the securechannel */ static void processOPN(UA_Server *server, UA_Connection *connection, UA_UInt32 channelId, const UA_ByteString *msg) { UA_StatusCode retval = UA_STATUSCODE_GOOD; /* Called before HEL */ if(connection->state != UA_CONNECTION_ESTABLISHED) retval = UA_STATUSCODE_BADCOMMUNICATIONERROR; /* Opening up a channel with a channelid already set */ if(!connection->channel && channelId != 0) retval = UA_STATUSCODE_BADCOMMUNICATIONERROR; /* Renew a channel with the wrong channelid */ if(connection->channel && channelId != connection->channel->securityToken.channelId) retval = UA_STATUSCODE_BADCOMMUNICATIONERROR; /* Decode the request */ UA_AsymmetricAlgorithmSecurityHeader asymHeader; UA_SequenceHeader seqHeader; UA_NodeId requestType; UA_OpenSecureChannelRequest r; size_t offset = 0; retval |= UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(msg, &offset, &asymHeader); retval |= UA_SequenceHeader_decodeBinary(msg, &offset, &seqHeader); retval |= UA_NodeId_decodeBinary(msg, &offset, &requestType); retval |= UA_OpenSecureChannelRequest_decodeBinary(msg, &offset, &r); /* Error occured */ if(retval != UA_STATUSCODE_GOOD || requestType.identifier.numeric != 446) { UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_NodeId_deleteMembers(&requestType); UA_OpenSecureChannelRequest_deleteMembers(&r); connection->close(connection); return; } /* Call the service */ UA_OpenSecureChannelResponse p; UA_OpenSecureChannelResponse_init(&p); Service_OpenSecureChannel(server, connection, &r, &p); UA_OpenSecureChannelRequest_deleteMembers(&r); /* Opening the channel failed */ UA_SecureChannel *channel = connection->channel; if(!channel) { UA_OpenSecureChannelResponse_deleteMembers(&p); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); connection->close(connection); return; } /* Set the starting sequence number */ channel->receiveSequenceNumber = seqHeader.sequenceNumber; /* Allocate the return message */ UA_ByteString resp_msg; UA_ByteString_init(&resp_msg); retval = connection->getSendBuffer(connection, connection->localConf.sendBufferSize, &resp_msg); if(retval != UA_STATUSCODE_GOOD) { UA_OpenSecureChannelResponse_deleteMembers(&p); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); connection->close(connection); return; } /* Encode the message after the secureconversationmessageheader */ size_t tmpPos = 12; /* skip the header */ seqHeader.sequenceNumber = UA_atomic_add(&channel->sendSequenceNumber, 1); retval |= UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos); UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE].binaryEncodingId); retval |= UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos); retval |= UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos); if(retval != UA_STATUSCODE_GOOD) { connection->releaseSendBuffer(connection, &resp_msg); UA_OpenSecureChannelResponse_deleteMembers(&p); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); connection->close(connection); return; } /* Encode the secureconversationmessageheader (cannot fail) and send */ UA_SecureConversationMessageHeader respHeader; respHeader.messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL; respHeader.messageHeader.messageSize = (UA_UInt32)tmpPos; respHeader.secureChannelId = p.securityToken.channelId; tmpPos = 0; UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos); resp_msg.length = respHeader.messageHeader.messageSize; connection->send(connection, &resp_msg); /* Clean up */ UA_OpenSecureChannelResponse_deleteMembers(&p); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); }
static void processOPN(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) { if(connection->state != UA_CONNECTION_ESTABLISHED) { connection->close(connection); return; } UA_UInt32 secureChannelId; UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId); UA_AsymmetricAlgorithmSecurityHeader asymHeader; retval |= UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(msg, pos, &asymHeader); UA_SequenceHeader seqHeader; retval |= UA_SequenceHeader_decodeBinary(msg, pos, &seqHeader); UA_NodeId requestType; retval |= UA_NodeId_decodeBinary(msg, pos, &requestType); UA_OpenSecureChannelRequest r; retval |= UA_OpenSecureChannelRequest_decodeBinary(msg, pos, &r); if(retval != UA_STATUSCODE_GOOD || requestType.identifier.numeric != 446) { UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_SequenceHeader_deleteMembers(&seqHeader); UA_NodeId_deleteMembers(&requestType); UA_OpenSecureChannelRequest_deleteMembers(&r); connection->close(connection); return; } UA_OpenSecureChannelResponse p; UA_OpenSecureChannelResponse_init(&p); 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; respHeader.secureChannelId = p.securityToken.channelId; UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE + UA_ENCODINGOFFSET_BINARY); respHeader.messageHeader.messageSize = UA_SecureConversationMessageHeader_calcSizeBinary(&respHeader) + UA_AsymmetricAlgorithmSecurityHeader_calcSizeBinary(&asymHeader) + UA_SequenceHeader_calcSizeBinary(&seqHeader) + UA_NodeId_calcSizeBinary(&responseType) + UA_OpenSecureChannelResponse_calcSizeBinary(&p); UA_ByteString resp_msg; retval = connection->getBuffer(connection, &resp_msg, respHeader.messageHeader.messageSize); if(retval != UA_STATUSCODE_GOOD) { UA_OpenSecureChannelResponse_deleteMembers(&p); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); return; } size_t tmpPos = 0; UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos); UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos); // just mirror back UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos); UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos); UA_OpenSecureChannelResponse_deleteMembers(&p); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); connection->write(connection, &resp_msg); connection->releaseBuffer(connection, &resp_msg); }
static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) { /* Read in the securechannel */ UA_UInt32 secureChannelId; UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId); if(retval != UA_STATUSCODE_GOOD) return; /* the anonymous channel is used e.g. to allow getEndpoints without a channel */ UA_SecureChannel *clientChannel = connection->channel; UA_SecureChannel anonymousChannel; if(!clientChannel) { UA_SecureChannel_init(&anonymousChannel); anonymousChannel.connection = connection; clientChannel = &anonymousChannel; #ifdef EXTENSION_STATELESS anonymousChannel.session = &anonymousSession; #endif } /* Read the security header */ UA_UInt32 tokenId; UA_SequenceHeader sequenceHeader; retval = UA_UInt32_decodeBinary(msg, pos, &tokenId); retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader); if(retval != UA_STATUSCODE_GOOD) return; /* Read the request type */ UA_NodeId requestType; if(UA_NodeId_decodeBinary(msg, pos, &requestType) != UA_STATUSCODE_GOOD) return; if(requestType.identifierType != UA_NODEIDTYPE_NUMERIC) { UA_NodeId_deleteMembers(&requestType); return; } switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY) { case UA_NS0ID_GETENDPOINTSREQUEST: { UA_GetEndpointsRequest p; UA_GetEndpointsResponse r; if(UA_GetEndpointsRequest_decodeBinary(msg, pos, &p)) return; UA_GetEndpointsResponse_init(&r); init_response_header(&p.requestHeader, &r.responseHeader); Service_GetEndpoints(server, &p, &r); UA_GetEndpointsRequest_deleteMembers(&p); UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]); UA_GetEndpointsResponse_deleteMembers(&r); break; } case UA_NS0ID_FINDSERVERSREQUEST: { UA_FindServersRequest p; UA_FindServersResponse r; if(UA_FindServersRequest_decodeBinary(msg, pos, &p)) return; UA_FindServersResponse_init(&r); init_response_header(&p.requestHeader, &r.responseHeader); Service_FindServers(server, &p, &r); UA_FindServersRequest_deleteMembers(&p); UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]); UA_FindServersResponse_deleteMembers(&r); break; } case UA_NS0ID_CREATESESSIONREQUEST: { UA_CreateSessionRequest p; UA_CreateSessionResponse r; if(UA_CreateSessionRequest_decodeBinary(msg, pos, &p)) return; UA_CreateSessionResponse_init(&r); init_response_header(&p.requestHeader, &r.responseHeader); Service_CreateSession(server, clientChannel, &p, &r); UA_CreateSessionRequest_deleteMembers(&p); UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]); UA_CreateSessionResponse_deleteMembers(&r); break; } case UA_NS0ID_ACTIVATESESSIONREQUEST: { UA_ActivateSessionRequest p; UA_ActivateSessionResponse r; if(UA_ActivateSessionRequest_decodeBinary(msg, pos, &p)) return; UA_ActivateSessionResponse_init(&r); init_response_header(&p.requestHeader, &r.responseHeader); Service_ActivateSession(server, clientChannel, &p, &r); UA_ActivateSessionRequest_deleteMembers(&p); UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]); UA_ActivateSessionResponse_deleteMembers(&r); break; } case UA_NS0ID_CLOSESESSIONREQUEST: INVOKE_SERVICE(CloseSession, UA_TYPES_CLOSESESSIONRESPONSE); break; case UA_NS0ID_READREQUEST: INVOKE_SERVICE(Read, UA_TYPES_READRESPONSE); break; case UA_NS0ID_WRITEREQUEST: INVOKE_SERVICE(Write, UA_TYPES_WRITERESPONSE); break; case UA_NS0ID_BROWSEREQUEST: INVOKE_SERVICE(Browse, UA_TYPES_BROWSERESPONSE); break; case UA_NS0ID_BROWSENEXTREQUEST: INVOKE_SERVICE(BrowseNext, UA_TYPES_BROWSENEXTRESPONSE); break; case UA_NS0ID_ADDREFERENCESREQUEST: INVOKE_SERVICE(AddReferences, UA_TYPES_ADDREFERENCESRESPONSE); break; case UA_NS0ID_REGISTERNODESREQUEST: INVOKE_SERVICE(RegisterNodes, UA_TYPES_REGISTERNODESRESPONSE); break; case UA_NS0ID_UNREGISTERNODESREQUEST: INVOKE_SERVICE(UnregisterNodes, UA_TYPES_UNREGISTERNODESRESPONSE); break; case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST: INVOKE_SERVICE(TranslateBrowsePathsToNodeIds, UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE); break; default: { 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 UA_LOG_INFO(server->logger, UA_LOGCATEGORY_COMMUNICATION, "Unknown request: NodeId(ns=%d, i=%d)", requestType.namespaceIndex, requestType.identifier.numeric); UA_RequestHeader p; UA_ResponseHeader r; if(UA_RequestHeader_decodeBinary(msg, pos, &p) != UA_STATUSCODE_GOOD) return; UA_ResponseHeader_init(&r); init_response_header(&p, &r); r.serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED; #ifdef EXTENSION_STATELESS if(retval != UA_STATUSCODE_GOOD) r.serviceResult = retval; #endif UA_RequestHeader_deleteMembers(&p); UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_RESPONSEHEADER]); break; } } }
static int ua_client_connectUA(char* ipaddress,int port, UA_String *endpointUrl, ConnectionInfo *connectionInfo, UA_Boolean stateless, UA_Boolean udp) { UA_ByteString reply; UA_ByteString_newMembers(&reply, 65536); int sock; struct sockaddr_in server; //Create socket if(udp==UA_TRUE){ sock = socket(AF_INET, SOCK_DGRAM, 0); }else{ sock = socket(AF_INET, SOCK_STREAM, 0); } if(sock == -1) { printf("Could not create socket"); return 1; } server.sin_addr.s_addr = inet_addr(ipaddress); server.sin_family = AF_INET; server.sin_port = htons(port); if(connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { perror("connect failed. Error"); return 1; } connectionInfo->socket = sock; if(stateless){ UA_NodeId_init(&connectionInfo->authenticationToken); connectionInfo->channelId=0; UA_SequenceHeader_init(&connectionInfo->sequenceHdr); connectionInfo->tokenId=0; return 0; }else{ sendHello(sock, endpointUrl); recv(sock, reply.data, reply.length, 0); sendOpenSecureChannel(sock); recv(sock, reply.data, reply.length, 0); size_t recvOffset = 0; UA_TcpMessageHeader msghdr; UA_TcpMessageHeader_decodeBinary(&reply, &recvOffset, &msghdr); UA_AsymmetricAlgorithmSecurityHeader asymHeader; UA_NodeId rspType; UA_OpenSecureChannelResponse openSecChannelRsp; UA_UInt32_decodeBinary(&reply, &recvOffset, &connectionInfo->channelId); UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply,&recvOffset,&asymHeader); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_SequenceHeader_decodeBinary(&reply,&recvOffset,&connectionInfo->sequenceHdr); UA_NodeId_decodeBinary(&reply,&recvOffset,&rspType); UA_OpenSecureChannelResponse_decodeBinary(&reply,&recvOffset,&openSecChannelRsp); connectionInfo->tokenId = openSecChannelRsp.securityToken.tokenId; sendCreateSession(sock, connectionInfo->channelId, openSecChannelRsp.securityToken.tokenId, 52, 2, endpointUrl); recv(sock, reply.data, reply.length, 0); UA_NodeId messageType; recvOffset = 24; UA_NodeId_decodeBinary(&reply,&recvOffset,&messageType); UA_CreateSessionResponse createSessionResponse; UA_CreateSessionResponse_decodeBinary(&reply,&recvOffset,&createSessionResponse); connectionInfo->authenticationToken = createSessionResponse.authenticationToken; sendActivateSession(sock, connectionInfo->channelId, connectionInfo->tokenId, 53, 3, connectionInfo->authenticationToken); recv(sock, reply.data, reply.length, 0); UA_OpenSecureChannelResponse_deleteMembers(&openSecChannelRsp); UA_String_deleteMembers(&reply); UA_CreateSessionResponse_deleteMembers(&createSessionResponse); return 0; } }
static void processOPN(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) { if(connection->state != UA_CONNECTION_ESTABLISHED) { connection->close(connection); return; } UA_UInt32 secureChannelId; UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId); UA_AsymmetricAlgorithmSecurityHeader asymHeader; retval |= UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(msg, pos, &asymHeader); UA_SequenceHeader seqHeader; retval |= UA_SequenceHeader_decodeBinary(msg, pos, &seqHeader); UA_NodeId requestType; retval |= UA_NodeId_decodeBinary(msg, pos, &requestType); UA_OpenSecureChannelRequest r; retval |= UA_OpenSecureChannelRequest_decodeBinary(msg, pos, &r); if(retval != UA_STATUSCODE_GOOD || requestType.identifier.numeric != 446) { UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_SequenceHeader_deleteMembers(&seqHeader); UA_NodeId_deleteMembers(&requestType); UA_OpenSecureChannelRequest_deleteMembers(&r); connection->close(connection); return; } UA_OpenSecureChannelResponse p; UA_OpenSecureChannelResponse_init(&p); 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 */ #ifndef UA_MULTITHREADING seqHeader.sequenceNumber = ++channel->sequenceNumber; #else seqHeader.sequenceNumber = uatomic_add_return(&channel->sequenceNumber, 1); #endif UA_SecureConversationMessageHeader respHeader; respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF; respHeader.messageHeader.messageSize = 0; respHeader.secureChannelId = p.securityToken.channelId; UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE + UA_ENCODINGOFFSET_BINARY); UA_ByteString resp_msg; retval = connection->getSendBuffer(connection, connection->remoteConf.recvBufferSize, &resp_msg); if(retval != UA_STATUSCODE_GOOD) { UA_OpenSecureChannelResponse_deleteMembers(&p); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); return; } size_t tmpPos = 12; /* skip the secureconversationmessageheader for now */ retval |= UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos); // just mirror back retval |= UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos); retval |= UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos); if(retval != UA_STATUSCODE_GOOD) { connection->releaseSendBuffer(connection, &resp_msg); connection->close(connection); } else { respHeader.messageHeader.messageSize = tmpPos; tmpPos = 0; UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos); resp_msg.length = respHeader.messageHeader.messageSize; connection->send(connection, &resp_msg); } UA_OpenSecureChannelResponse_deleteMembers(&p); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); }
static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) { /* Read in the securechannel */ UA_UInt32 secureChannelId; UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId); if(retval != UA_STATUSCODE_GOOD) return; /* the anonymous channel is used e.g. to allow getEndpoints without a channel */ UA_SecureChannel *clientChannel = connection->channel; UA_SecureChannel anonymousChannel; if(!clientChannel) { UA_SecureChannel_init(&anonymousChannel); anonymousChannel.connection = connection; clientChannel = &anonymousChannel; } /* Read the security header */ UA_UInt32 tokenId = 0; UA_SequenceHeader sequenceHeader; retval = UA_UInt32_decodeBinary(msg, pos, &tokenId); retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader); #ifndef EXTENSION_STATELESS if(retval != UA_STATUSCODE_GOOD || tokenId == 0) // 0 is invalid return; #else if(retval != UA_STATUSCODE_GOOD) return; #endif if(clientChannel != &anonymousChannel && tokenId != clientChannel->securityToken.tokenId) { if(tokenId != clientChannel->nextSecurityToken.tokenId) { /* close the securechannel but keep the connection open */ UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SECURECHANNEL, "Request with a wrong security token. Closing the SecureChannel %i.", clientChannel->securityToken.channelId); Service_CloseSecureChannel(server, clientChannel->securityToken.channelId); return; } UA_SecureChannel_revolveTokens(clientChannel); } /* Read the request type */ UA_NodeId requestType; if(UA_NodeId_decodeBinary(msg, pos, &requestType) != UA_STATUSCODE_GOOD) return; if(requestType.identifierType != UA_NODEIDTYPE_NUMERIC) { UA_NodeId_deleteMembers(&requestType); return; } switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY) { case UA_NS0ID_GETENDPOINTSREQUEST: { if(clientChannel == &anonymousChannel) UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_NETWORK, "Processing GetEndpointsRequest on Connection %i", connection->sockfd); else UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SECURECHANNEL, "Processing GetEndpointsRequest on SecureChannel %i", clientChannel->securityToken.channelId); UA_GetEndpointsRequest p; UA_GetEndpointsResponse r; if(UA_GetEndpointsRequest_decodeBinary(msg, pos, &p)) return; UA_GetEndpointsResponse_init(&r); init_response_header(&p.requestHeader, &r.responseHeader); Service_GetEndpoints(server, &p, &r); UA_GetEndpointsRequest_deleteMembers(&p); UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]); UA_GetEndpointsResponse_deleteMembers(&r); break; } case UA_NS0ID_FINDSERVERSREQUEST: { if(clientChannel == &anonymousChannel) UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_NETWORK, "Processing FindServerRequest on Connection %i", connection->sockfd); else UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SECURECHANNEL, "Processing FindServerRequest on SecureChannel %i", clientChannel->securityToken.channelId); UA_FindServersRequest p; UA_FindServersResponse r; if(UA_FindServersRequest_decodeBinary(msg, pos, &p)) return; UA_FindServersResponse_init(&r); init_response_header(&p.requestHeader, &r.responseHeader); Service_FindServers(server, &p, &r); UA_FindServersRequest_deleteMembers(&p); UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]); UA_FindServersResponse_deleteMembers(&r); break; } case UA_NS0ID_CREATESESSIONREQUEST: { UA_CreateSessionRequest p; UA_CreateSessionResponse r; if(UA_CreateSessionRequest_decodeBinary(msg, pos, &p)) return; UA_CreateSessionResponse_init(&r); init_response_header(&p.requestHeader, &r.responseHeader); Service_CreateSession(server, clientChannel, &p, &r); UA_CreateSessionRequest_deleteMembers(&p); UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]); UA_CreateSessionResponse_deleteMembers(&r); break; } case UA_NS0ID_ACTIVATESESSIONREQUEST: { UA_ActivateSessionRequest p; UA_ActivateSessionResponse r; if(UA_ActivateSessionRequest_decodeBinary(msg, pos, &p)) return; UA_ActivateSessionResponse_init(&r); init_response_header(&p.requestHeader, &r.responseHeader); Service_ActivateSession(server, clientChannel, &p, &r); UA_ActivateSessionRequest_deleteMembers(&p); UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]); UA_ActivateSessionResponse_deleteMembers(&r); break; } case UA_NS0ID_CLOSESESSIONREQUEST: INVOKE_SERVICE(CloseSession, UA_TYPES_CLOSESESSIONRESPONSE); break; case UA_NS0ID_READREQUEST: INVOKE_SERVICE(Read, UA_TYPES_READRESPONSE); break; case UA_NS0ID_WRITEREQUEST: INVOKE_SERVICE(Write, UA_TYPES_WRITERESPONSE); break; case UA_NS0ID_BROWSEREQUEST: INVOKE_SERVICE(Browse, UA_TYPES_BROWSERESPONSE); break; case UA_NS0ID_BROWSENEXTREQUEST: INVOKE_SERVICE(BrowseNext, UA_TYPES_BROWSENEXTRESPONSE); break; case UA_NS0ID_REGISTERNODESREQUEST: INVOKE_SERVICE(RegisterNodes, UA_TYPES_REGISTERNODESRESPONSE); break; case UA_NS0ID_UNREGISTERNODESREQUEST: INVOKE_SERVICE(UnregisterNodes, UA_TYPES_UNREGISTERNODESRESPONSE); break; case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST: INVOKE_SERVICE(TranslateBrowsePathsToNodeIds, UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE); break; #ifdef ENABLE_SUBSCRIPTIONS case UA_NS0ID_CREATESUBSCRIPTIONREQUEST: INVOKE_SERVICE(CreateSubscription, UA_TYPES_CREATESUBSCRIPTIONRESPONSE); break; case UA_NS0ID_PUBLISHREQUEST: INVOKE_SERVICE(Publish, UA_TYPES_PUBLISHRESPONSE); break; case UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST: INVOKE_SERVICE(ModifySubscription, UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE); break; case UA_NS0ID_DELETESUBSCRIPTIONSREQUEST: INVOKE_SERVICE(DeleteSubscriptions, UA_TYPES_DELETESUBSCRIPTIONSRESPONSE); break; case UA_NS0ID_CREATEMONITOREDITEMSREQUEST: INVOKE_SERVICE(CreateMonitoredItems, UA_TYPES_CREATEMONITOREDITEMSRESPONSE); break; case UA_NS0ID_DELETEMONITOREDITEMSREQUEST: INVOKE_SERVICE(DeleteMonitoredItems, UA_TYPES_DELETEMONITOREDITEMSRESPONSE); break; #endif #ifdef ENABLE_METHODCALLS case UA_NS0ID_CALLREQUEST: INVOKE_SERVICE(Call, UA_TYPES_CALLRESPONSE); break; #endif #ifdef ENABLE_NODEMANAGEMENT case UA_NS0ID_ADDNODESREQUEST: INVOKE_SERVICE(AddNodes, UA_TYPES_ADDNODESRESPONSE); break; case UA_NS0ID_ADDREFERENCESREQUEST: INVOKE_SERVICE(AddReferences, UA_TYPES_ADDREFERENCESRESPONSE); break; case UA_NS0ID_DELETENODESREQUEST: INVOKE_SERVICE(DeleteNodes, UA_TYPES_DELETENODESRESPONSE); break; case UA_NS0ID_DELETEREFERENCESREQUEST: INVOKE_SERVICE(DeleteReferences, UA_TYPES_DELETEREFERENCESRESPONSE); break; #endif default: { if(requestType.namespaceIndex == 0 && requestType.identifier.numeric==787) UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK, "Client requested a subscription that are not supported, the message will be skipped"); else UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK, "Unknown request: NodeId(ns=%d, i=%d)", requestType.namespaceIndex, requestType.identifier.numeric); UA_RequestHeader p; UA_ServiceFault r; if(UA_RequestHeader_decodeBinary(msg, pos, &p) != UA_STATUSCODE_GOOD) return; UA_ServiceFault_init(&r); init_response_header(&p, &r.responseHeader); r.responseHeader.serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED; UA_SecureChannel_sendBinaryMessage(clientChannel, sequenceHeader.requestId, &r, &UA_TYPES[UA_TYPES_SERVICEFAULT]); UA_RequestHeader_deleteMembers(&p); UA_ServiceFault_deleteMembers(&r); break; } } }
static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) { /* If we cannot decode these, don't respond */ UA_UInt32 secureChannelId = 0; UA_UInt32 tokenId = 0; UA_SequenceHeader sequenceHeader; UA_NodeId requestTypeId; UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId); retval |= UA_UInt32_decodeBinary(msg, pos, &tokenId); retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader); retval = UA_NodeId_decodeBinary(msg, pos, &requestTypeId); if(retval != UA_STATUSCODE_GOOD) return; UA_SecureChannel *channel = connection->channel; UA_SecureChannel anonymousChannel; if(!channel) { UA_SecureChannel_init(&anonymousChannel); anonymousChannel.connection = connection; channel = &anonymousChannel; } /* Test if the secure channel is ok */ if(secureChannelId != channel->securityToken.channelId) return; if(tokenId != channel->securityToken.tokenId) { if(tokenId != channel->nextSecurityToken.tokenId) { /* close the securechannel but keep the connection open */ UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SECURECHANNEL, "Request with a wrong security token. Closing the SecureChannel %i.", channel->securityToken.channelId); Service_CloseSecureChannel(server, channel->securityToken.channelId); return; } UA_SecureChannel_revolveTokens(channel); } /* Test if the service type nodeid has the right format */ if(requestTypeId.identifierType != UA_NODEIDTYPE_NUMERIC || requestTypeId.namespaceIndex != 0) { UA_NodeId_deleteMembers(&requestTypeId); sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED); return; } /* Get the service pointers */ UA_Service service = NULL; const UA_DataType *requestType = NULL; const UA_DataType *responseType = NULL; getServicePointers(requestTypeId.identifier.numeric, &requestType, &responseType, &service); if(!service) { /* The service is not supported */ if(requestTypeId.identifier.numeric==787) UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client requested a subscription that are not supported, " "the message will be skipped"); else UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Unknown request: NodeId(ns=%d, i=%d)", requestTypeId.namespaceIndex, requestTypeId.identifier.numeric); sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED); return; } /* Most services can only be called with a valid securechannel */ #ifndef EXTENSION_STATELESS if(channel == &anonymousChannel && requestType->typeIndex > UA_TYPES_OPENSECURECHANNELREQUEST) { sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSECURECHANNELIDINVALID); return; } #endif /* Decode the request */ void *request = UA_alloca(requestType->memSize); size_t oldpos = *pos; retval = UA_decodeBinary(msg, pos, request, requestType); if(retval != UA_STATUSCODE_GOOD) { sendError(channel, msg, oldpos, sequenceHeader.requestId, retval); return; } /* Find the matching session */ UA_Session *session = UA_SecureChannel_getSession(channel, &((UA_RequestHeader*)request)->authenticationToken); UA_Session anonymousSession; if(!session) { UA_Session_init(&anonymousSession); anonymousSession.channel = channel; anonymousSession.activated = UA_TRUE; session = &anonymousSession; } /* Test if the session is valid */ if(!session->activated && requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST) { UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service with a non-activated session"); sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED); return; } #ifndef EXTENSION_STATELESS if(session == &anonymousSession && requestType->typeIndex > UA_TYPES_ACTIVATESESSIONREQUEST) { UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service without a session"); sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONIDINVALID); return; } #endif /* Call the service */ UA_Session_updateLifetime(session); void *response = UA_alloca(responseType->memSize); UA_init(response, responseType); init_response_header(request, response); service(server, session, request, response); /* Send the response */ retval = UA_SecureChannel_sendBinaryMessage(channel, sequenceHeader.requestId, response, responseType); if(retval != UA_STATUSCODE_GOOD) { /* e.g. UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED */ sendError(channel, msg, oldpos, sequenceHeader.requestId, retval); } /* Clean up */ UA_deleteMembers(request, requestType); UA_deleteMembers(response, responseType); return; }