/* The request/response are casted to the header (first element of their struct) */ static void invoke_service(UA_Server *server, UA_SecureChannel *channel, 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); 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); if(!session) session = UA_SessionManager_getSession(&server->sessionManager, &request->authenticationToken); if(!session) response->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID; else if(session->activated == UA_FALSE) { response->serviceResult = UA_STATUSCODE_BADSESSIONNOTACTIVATED; /* the session is invalidated FIXME: do this delayed*/ UA_SessionManager_removeSession(&server->sessionManager, &request->authenticationToken); } else if(session->channel != channel) { response->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID; } else { UA_Session_updateLifetime(session); service(server, session, request, response); } UA_SecureChannel_sendBinaryMessage(channel, requestId, response, responseType); UA_deleteMembers(response, responseType); }
/* The request/response are casted to the header (first element of their struct) */ static void invoke_service(UA_Server *server, UA_SecureChannel *channel, 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); 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); #ifdef EXTENSION_STATELESS if(request->authenticationToken.namespaceIndex == 0 && request->authenticationToken.identifierType == UA_NODEIDTYPE_NUMERIC && request->authenticationToken.identifier.numeric == 0 && (responseType->typeIndex == UA_TYPES_READRESPONSE || responseType->typeIndex == UA_TYPES_WRITERESPONSE || responseType->typeIndex == UA_TYPES_BROWSERESPONSE) ){ session = &anonymousSession; service(server, session, request, response); }else{ #endif if(!session || session->channel != channel) { response->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID; } else if(session->activated == UA_FALSE) { response->serviceResult = UA_STATUSCODE_BADSESSIONNOTACTIVATED; /* /\* the session is invalidated FIXME: do this delayed*\/ */ /* UA_SessionManager_removeSession(&server->sessionManager, server, &request->authenticationToken); */ } else { UA_Session_updateLifetime(session); service(server, session, request, response); } #ifdef EXTENSION_STATELESS } #endif UA_StatusCode retval = UA_SecureChannel_sendBinaryMessage(channel, requestId, response, responseType); if(retval != UA_STATUSCODE_GOOD) { if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) response->serviceResult = UA_STATUSCODE_BADRESPONSETOOLARGE; else response->serviceResult = retval; UA_SecureChannel_sendBinaryMessage(channel, requestId, response, &UA_TYPES[UA_TYPES_SERVICEFAULT]); } UA_deleteMembers(response, responseType); }
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); }
static UA_StatusCode CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_WriteValue *wvalue) { if(!wvalue->value.hasValue) return UA_STATUSCODE_BADNODATA; void *value = wvalue->value.value.data; void *target = NULL; const UA_DataType *type = NULL; UA_StatusCode retval = UA_STATUSCODE_GOOD; switch(wvalue->attributeId) { case UA_ATTRIBUTEID_NODEID: case UA_ATTRIBUTEID_NODECLASS: case UA_ATTRIBUTEID_DATATYPE: retval = UA_STATUSCODE_BADWRITENOTSUPPORTED; break; case UA_ATTRIBUTEID_BROWSENAME: CHECK_DATATYPE(QUALIFIEDNAME); target = &node->browseName; type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME]; break; case UA_ATTRIBUTEID_DISPLAYNAME: CHECK_DATATYPE(LOCALIZEDTEXT); target = &node->displayName; type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]; break; case UA_ATTRIBUTEID_DESCRIPTION: CHECK_DATATYPE(LOCALIZEDTEXT); target = &node->description; type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]; break; case UA_ATTRIBUTEID_WRITEMASK: CHECK_DATATYPE(UINT32); node->writeMask = *(UA_UInt32*)value; break; case UA_ATTRIBUTEID_USERWRITEMASK: CHECK_DATATYPE(UINT32); node->userWriteMask = *(UA_UInt32*)value; break; case UA_ATTRIBUTEID_ISABSTRACT: CHECK_NODECLASS_WRITE(UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE); CHECK_DATATYPE(BOOLEAN); ((UA_ObjectTypeNode*)node)->isAbstract = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_SYMMETRIC: CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE); CHECK_DATATYPE(BOOLEAN); ((UA_ReferenceTypeNode*)node)->symmetric = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_INVERSENAME: CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE); CHECK_DATATYPE(LOCALIZEDTEXT); target = &((UA_ReferenceTypeNode*)node)->inverseName; type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]; break; case UA_ATTRIBUTEID_CONTAINSNOLOOPS: CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW); CHECK_DATATYPE(BOOLEAN); ((UA_ViewNode*)node)->containsNoLoops = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_EVENTNOTIFIER: CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT); CHECK_DATATYPE(BYTE); ((UA_ViewNode*)node)->eventNotifier = *(UA_Byte*)value; break; case UA_ATTRIBUTEID_VALUE: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE); if(((const UA_VariableNode*)node)->valueSource == UA_VALUESOURCE_VARIANT) retval = CopyValueIntoNode((UA_VariableNode*)node, wvalue); else retval = Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)node, wvalue); break; case UA_ATTRIBUTEID_ACCESSLEVEL: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_DATATYPE(BYTE); ((UA_VariableNode*)node)->accessLevel = *(UA_Byte*)value; break; case UA_ATTRIBUTEID_USERACCESSLEVEL: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_DATATYPE(BYTE); ((UA_VariableNode*)node)->userAccessLevel = *(UA_Byte*)value; break; case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_DATATYPE(DOUBLE); ((UA_VariableNode*)node)->minimumSamplingInterval = *(UA_Double*)value; break; case UA_ATTRIBUTEID_HISTORIZING: CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE); CHECK_DATATYPE(BOOLEAN); ((UA_VariableNode*)node)->historizing = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_EXECUTABLE: CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD); CHECK_DATATYPE(BOOLEAN); ((UA_MethodNode*)node)->executable = *(UA_Boolean*)value; break; case UA_ATTRIBUTEID_USEREXECUTABLE: CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD); CHECK_DATATYPE(BOOLEAN); ((UA_MethodNode*)node)->userExecutable = *(UA_Boolean*)value; break; default: retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; break; } if(type) { UA_deleteMembers(target, type); retval = UA_copy(value, target, type); } return retval; }
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; }