OV_DLLFNCEXPORT UA_StatusCode propertyValueStatementOPCUAInterface_interface_ovExpressionSemanticNodeToOPCUA( void *handle, const UA_NodeId *nodeId, UA_Node** opcuaNode) { UA_Node *newNode = NULL; UA_StatusCode result = UA_STATUSCODE_GOOD; OV_PATH path; OV_INSTPTR_ov_object pobj = NULL; OV_TICKET *pTicket = NULL; OV_VTBLPTR_ov_object pVtblObj = NULL; OV_ACCESS access; UA_NodeClass nodeClass; OV_ELEMENT element; ov_memstack_lock(); result = opcua_nodeStoreFunctions_resolveNodeIdToPath(*nodeId, &path); if(result != UA_STATUSCODE_GOOD){ ov_memstack_unlock(); return result; } element = path.elements[path.size-1]; ov_memstack_unlock(); result = opcua_nodeStoreFunctions_getVtblPointerAndCheckAccess(&(element), pTicket, &pobj, &pVtblObj, &access); if(result != UA_STATUSCODE_GOOD){ return result; } nodeClass = UA_NODECLASS_VARIABLE; newNode = (UA_Node*)UA_calloc(1, sizeof(UA_VariableNode)); // Basic Attribute // BrowseName UA_QualifiedName qName; qName.name = UA_String_fromChars(pobj->v_identifier); qName.namespaceIndex = nodeId->namespaceIndex; newNode->browseName = qName; // Description // Description OV_STRING tempString = pVtblObj->m_getcomment(pobj, &element); UA_LocalizedText lText; UA_LocalizedText_init(&lText); lText.locale = UA_String_fromChars("en"); if(tempString){ lText.text = UA_String_fromChars(tempString); } else { lText.text = UA_String_fromChars(""); } UA_LocalizedText_copy(&lText,&newNode->description); UA_LocalizedText_deleteMembers(&lText); // DisplayName UA_LocalizedText displayName; UA_LocalizedText_init(&displayName); displayName.locale = UA_String_fromChars("en"); displayName.text = UA_String_fromChars(pobj->v_identifier); UA_LocalizedText_copy(&displayName, &newNode->displayName); UA_LocalizedText_deleteMembers(&displayName); // NodeId UA_NodeId_copy(nodeId, &newNode->nodeId); // NodeClass newNode->nodeClass = nodeClass; // WriteMask UA_UInt32 writeMask = 0; if(element.elemtype != OV_ET_VARIABLE){ if(access & OV_AC_WRITE){ writeMask |= (1<<2); // BrowseName writeMask |= (1<<6); // DisplayName } if(access & OV_AC_RENAMEABLE){ writeMask |= (1<<14); // NodeId } } newNode->writeMask = writeMask; // Variable specific attributes // arrayDemensions ((UA_VariableNode*)newNode)->arrayDimensionsSize = 0; ((UA_VariableNode*)newNode)->arrayDimensions = NULL; // UA_Array_new(((UA_VariableNode*)newNode)->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]); /* scalar or one dimension */ // valuerank ((UA_VariableNode*)newNode)->valueRank = 1; /* one dimension */ // value OV_ELEMENT tmpPart; tmpPart.elemtype = OV_ET_NONE; OV_ELEMENT tmpParrent; tmpParrent.pobj = pobj; tmpParrent.elemtype = OV_ET_OBJECT; UA_ExpressionSemanticEnum tmpExpressionSemantic = 0; do { ov_element_getnextpart(&tmpParrent, &tmpPart, OV_ET_VARIABLE); if (tmpPart.elemtype == OV_ET_NONE) break; if (ov_string_compare(tmpPart.elemunion.pvar->v_identifier, "ExpressionSemanticEnum") == OV_STRCMP_EQUAL){ tmpExpressionSemantic = *(UA_UInt32*)tmpPart.pvalue; break; } } while(TRUE); ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->type = &UA_PROPERTYVALUESTATEMENT[UA_PROPERTYVALUESTATEMENT_EXPRESSIONSEMANTICENUM]; ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data = UA_ExpressionSemanticEnum_new(); if (!((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data){ result = UA_STATUSCODE_BADOUTOFMEMORY; return result; } ((UA_VariableNode*)newNode)->value.data.value.hasValue = TRUE; ((UA_VariableNode*)newNode)->valueSource = UA_VALUESOURCE_DATA; UA_ExpressionSemanticEnum_copy(&tmpExpressionSemantic, ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data); UA_ExpressionSemanticEnum_deleteMembers(&tmpExpressionSemantic); // accessLevel UA_Byte accessLevel = 0; if(access & OV_AC_READ){ accessLevel |= (1<<0); } if(access & OV_AC_WRITE){ accessLevel |= (1<<1); } ((UA_VariableNode*)newNode)->accessLevel = accessLevel; // minimumSamplingInterval ((UA_VariableNode*)newNode)->minimumSamplingInterval = -1; // historizing ((UA_VariableNode*)newNode)->historizing = UA_FALSE; // dataType ((UA_VariableNode*)newNode)->dataType = UA_NODEID_NUMERIC(pinterface->v_modelnamespace.index, UA_NSPROPERTYVALUESTATEMENTID_EXPRESSIONSEMANTICENUM); // References addReference(newNode); OV_UINT len = 0; OV_STRING *plist = NULL; OV_STRING tmpString = NULL; copyOPCUAStringToOV(nodeId->identifier.string, &tmpString); plist = ov_string_split(tmpString, "/", &len); ov_string_setvalue(&tmpString, plist[0]); for (OV_UINT i = 1; i < len-1; i++){ ov_string_append(&tmpString, "/"); ov_string_append(&tmpString, plist[i]); } ov_string_freelist(plist); UA_NodeId tmpNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); for (size_t i = 0; i < newNode->referencesSize; i++){ if (UA_NodeId_equal(&newNode->references[i].referenceTypeId, &tmpNodeId)){ newNode->references[i].targetId = UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE); continue; } OV_STRING tmpString2 = NULL; copyOPCUAStringToOV(newNode->references[i].targetId.nodeId.identifier.string, &tmpString2); if (ov_string_compare(tmpString, tmpString2) == OV_STRCMP_EQUAL && newNode->references[i].isInverse == UA_TRUE){ newNode->references[i].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); } ov_string_setvalue(&tmpString2, NULL); } ov_string_setvalue(&tmpString, NULL); UA_NodeId_deleteMembers(&tmpNodeId); *opcuaNode = newNode; return UA_STATUSCODE_GOOD; }
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); }
int main(int argc, char *argv[]) { UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new()); UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect, "opc.tcp://localhost:16664"); if(retval != UA_STATUSCODE_GOOD) { UA_Client_delete(client); return retval; } // Browse some objects printf("Browsing nodes in objects folder:\n"); UA_BrowseRequest bReq; UA_BrowseRequest_init(&bReq); bReq.requestedMaxReferencesPerNode = 0; bReq.nodesToBrowse = UA_BrowseDescription_new(); bReq.nodesToBrowseSize = 1; bReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); //browse objects folder bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything UA_BrowseResponse bResp = UA_Client_browse(client, &bReq); printf("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME"); for (int i = 0; i < bResp.resultsSize; ++i) { for (int j = 0; j < bResp.results[i].referencesSize; ++j) { UA_ReferenceDescription *ref = &(bResp.results[i].references[j]); if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC) { printf("%-9d %-16d %-16.*s %-16.*s\n", ref->browseName.namespaceIndex, ref->nodeId.nodeId.identifier.numeric, ref->browseName.name.length, ref->browseName.name.data, ref->displayName.text.length, ref->displayName.text.data); } else if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING) { printf("%-9d %-16.*s %-16.*s %-16.*s\n", ref->browseName.namespaceIndex, ref->nodeId.nodeId.identifier.string.length, ref->nodeId.nodeId.identifier.string.data, ref->browseName.name.length, ref->browseName.name.data, ref->displayName.text.length, ref->displayName.text.data); } //TODO: distinguish further types } } UA_BrowseRequest_deleteMembers(&bReq); UA_BrowseResponse_deleteMembers(&bResp); #ifdef ENABLE_SUBSCRIPTIONS // Create a subscription with interval 0 (immediate)... UA_Int32 subId = UA_Client_newSubscription(client, 0); if (subId) printf("Create subscription succeeded, id %u\n", subId); // .. and monitor TheAnswer UA_NodeId monitorThis; monitorThis = UA_NODEID_STRING_ALLOC(1, "the.answer"); UA_UInt32 monId = UA_Client_monitorItemChanges(client, subId, monitorThis, UA_ATTRIBUTEID_VALUE, &handler_TheAnswerChanged ); if (monId) printf("Monitoring 'the.answer', id %u\n", subId); UA_NodeId_deleteMembers(&monitorThis); // First Publish always generates data (current value) and call out handler. UA_Client_doPublish(client); // This should not generate anything UA_Client_doPublish(client); #endif UA_Int32 value = 0; // Read node's value printf("\nReading the value of node (1, \"the.answer\"):\n"); UA_ReadRequest rReq; UA_ReadRequest_init(&rReq); rReq.nodesToRead = UA_ReadValueId_new(); rReq.nodesToReadSize = 1; rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */ rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE; UA_ReadResponse rResp = UA_Client_read(client, &rReq); if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD && rResp.resultsSize > 0 && rResp.results[0].hasValue && UA_Variant_isScalar(&rResp.results[0].value) && rResp.results[0].value.type == &UA_TYPES[UA_TYPES_INT32]) { value = *(UA_Int32*)rResp.results[0].value.data; printf("the value is: %i\n", value); } UA_ReadRequest_deleteMembers(&rReq); UA_ReadResponse_deleteMembers(&rResp); value++; // Write node's value printf("\nWriting a value of node (1, \"the.answer\"):\n"); UA_WriteRequest wReq; UA_WriteRequest_init(&wReq); wReq.nodesToWrite = UA_WriteValue_new(); wReq.nodesToWriteSize = 1; wReq.nodesToWrite[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */ wReq.nodesToWrite[0].attributeId = UA_ATTRIBUTEID_VALUE; wReq.nodesToWrite[0].value.hasValue = UA_TRUE; wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT32]; wReq.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; //do not free the integer on deletion wReq.nodesToWrite[0].value.value.data = &value; UA_WriteResponse wResp = UA_Client_write(client, &wReq); if(wResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD) printf("the new value is: %i\n", value); UA_WriteRequest_deleteMembers(&wReq); UA_WriteResponse_deleteMembers(&wResp); #ifdef ENABLE_SUBSCRIPTIONS // Take another look at the.answer... this should call the handler. UA_Client_doPublish(client); // Delete our subscription (which also unmonitors all items) if(!UA_Client_removeSubscription(client, subId)) printf("Subscription removed\n"); #endif #ifdef ENABLE_METHODCALLS /* Note: This example requires Namespace 0 Node 11489 (ServerType -> GetMonitoredItems) FIXME: Provide a namespace 0 independant example on the server side */ UA_Variant input; UA_String argString = UA_STRING("Hello Server"); UA_Variant_init(&input); UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]); UA_Int32 outputSize; UA_Variant *output; retval = UA_Client_CallServerMethod(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output); if(retval == UA_STATUSCODE_GOOD) { printf("Method call was successfull, and %i returned values available.\n", outputSize); UA_Array_delete(output, &UA_TYPES[UA_TYPES_VARIANT], outputSize); } else { printf("Method call was unsuccessfull, and %x returned values available.\n", retval); } UA_Variant_deleteMembers(&input); #endif #ifdef ENABLE_ADDNODES /* Create a new object type node */ // New ReferenceType UA_AddNodesResponse *adResp = UA_Client_createReferenceTypeNode(client, UA_EXPANDEDNODEID_NUMERIC(1, 12133), // Assign this NodeId (will fail if client is called multiple times) UA_QUALIFIEDNAME(0, "NewReference"), UA_LOCALIZEDTEXT("en_US", "TheNewReference"), UA_LOCALIZEDTEXT("en_US", "References something that might or might not exist."), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), (UA_UInt32) 0, (UA_UInt32) 0, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_LOCALIZEDTEXT("en_US", "IsNewlyReferencedBy")); if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) { printf("Created 'NewReference' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric ); } UA_AddNodesResponse_deleteMembers(adResp); free(adResp); // New ObjectType adResp = UA_Client_createObjectTypeNode(client, UA_EXPANDEDNODEID_NUMERIC(1, 12134), // Assign this NodeId (will fail if client is called multiple times) UA_QUALIFIEDNAME(0, "NewObjectType"), UA_LOCALIZEDTEXT("en_US", "TheNewObjectType"), UA_LOCALIZEDTEXT("en_US", "Put innovative description here."), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), (UA_UInt32) 0, (UA_UInt32) 0, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)); if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) { printf("Created 'NewObjectType' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric ); } // New Object adResp = UA_Client_createObjectNode(client, UA_EXPANDEDNODEID_NUMERIC(1, 0), // Assign new/random NodeID UA_QUALIFIEDNAME(0, "TheNewGreatNodeBrowseName"), UA_LOCALIZEDTEXT("en_US", "TheNewGreatNode"), UA_LOCALIZEDTEXT("de_DE", "Hier koennte Ihre Webung stehen!"), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), (UA_UInt32) 0, (UA_UInt32) 0, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER)); if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) { printf("Created 'NewObject' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric ); } UA_AddNodesResponse_deleteMembers(adResp); free(adResp); // New Integer Variable UA_Variant *theValue = UA_Variant_new(); UA_Int32 *theValueDate = UA_Int32_new(); *theValueDate = 1234; theValue->type = &UA_TYPES[UA_TYPES_INT32]; theValue->data = theValueDate; adResp = UA_Client_createVariableNode(client, UA_EXPANDEDNODEID_NUMERIC(1, 0), // Assign new/random NodeID UA_QUALIFIEDNAME(0, "VariableNode"), UA_LOCALIZEDTEXT("en_US", "TheNewVariableNode"), UA_LOCALIZEDTEXT("en_US", "This integer is just amazing - it has digits and everything."), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), (UA_UInt32) 0, (UA_UInt32) 0, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_INT32), theValue); if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) { printf("Created 'NewVariable' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric ); } UA_AddNodesResponse_deleteMembers(adResp); free(adResp); free(theValue); /* Done creating a new node*/ #endif UA_Client_disconnect(client); UA_Client_delete(client); return UA_STATUSCODE_GOOD; }
void UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId, UA_AddNodesResult *result) { if(node->nodeId.namespaceIndex >= server->namespacesSize) { result->statusCode = UA_STATUSCODE_BADNODEIDINVALID; return; } const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentNodeId); if(!parent) { result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID; return; } const UA_ReferenceTypeNode *referenceType = (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId); if(!referenceType) { result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; return; } if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) { result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID; return; } if(referenceType->isAbstract == UA_TRUE) { result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED; return; } // todo: test if the referencetype is hierarchical // todo: namespace index is assumed to be valid UA_MT_CONST UA_Node *managed = NULL; UA_NodeId tempNodeid = node->nodeId; tempNodeid.namespaceIndex = 0; if(UA_NodeId_isNull(&tempNodeid)) { if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) { result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; return; } result->addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric } else { if(UA_NodeId_copy(&node->nodeId, &result->addedNodeId) != UA_STATUSCODE_GOOD) { result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; return; } if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) { result->statusCode = UA_STATUSCODE_BADNODEIDEXISTS; UA_NodeId_deleteMembers(&result->addedNodeId); return; } } /* Careful. The node is inserted. If the nodestore makes an expand, nodes change their address */ // reference back to the parent UA_AddReferencesItem item; UA_AddReferencesItem_init(&item); item.sourceNodeId = managed->nodeId; item.referenceTypeId = *referenceTypeId; item.isForward = UA_FALSE; item.targetNodeId.nodeId = *parentNodeId; Service_AddReferences_single(server, session, &item); // todo: error handling. remove new node from nodestore }
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; } } }
UaNodeId::~UaNodeId () { UA_NodeId_deleteMembers( &m_impl ); }
UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node **inserted) { size_t nodesize; /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */ switch(node->nodeClass) { case UA_NODECLASS_OBJECT: nodesize = sizeof(UA_ObjectNode); break; case UA_NODECLASS_VARIABLE: nodesize = sizeof(UA_VariableNode); break; case UA_NODECLASS_METHOD: nodesize = sizeof(UA_MethodNode); break; case UA_NODECLASS_OBJECTTYPE: nodesize = sizeof(UA_ObjectTypeNode); break; case UA_NODECLASS_VARIABLETYPE: nodesize = sizeof(UA_VariableTypeNode); break; case UA_NODECLASS_REFERENCETYPE: nodesize = sizeof(UA_ReferenceTypeNode); break; case UA_NODECLASS_DATATYPE: nodesize = sizeof(UA_DataTypeNode); break; case UA_NODECLASS_VIEW: nodesize = sizeof(UA_ViewNode); break; default: return UA_STATUSCODE_BADINTERNALERROR; } struct nodeEntry *entry; if(!(entry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize))) return UA_STATUSCODE_BADOUTOFMEMORY; memcpy((void*)&entry->node, node, nodesize); cds_lfht_node_init(&entry->htn); entry->refcount = ALIVE_BIT; if(inserted) // increase the counter before adding the node entry->refcount++; struct cds_lfht_node *result; //FIXME: a bit dirty workaround of preserving namespace //namespace index is assumed to be valid UA_NodeId tempNodeid; UA_NodeId_copy(&node->nodeId, &tempNodeid); tempNodeid.namespaceIndex = 0; if(!UA_NodeId_isNull(&tempNodeid)) { hash_t h = hash(&node->nodeId); rcu_read_lock(); result = cds_lfht_add_unique(ns->ht, h, compare, &entry->node.nodeId, &entry->htn); rcu_read_unlock(); /* If the nodeid exists already */ if(result != &entry->htn) { UA_free(entry); return UA_STATUSCODE_BADNODEIDEXISTS; } } else { /* create a unique nodeid */ ((UA_Node *)&entry->node)->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC; if(((UA_Node *)&entry->node)->nodeId.namespaceIndex == 0) //original request for ns=0 should yield ns=1 ((UA_Node *)&entry->node)->nodeId.namespaceIndex = 1; if(((UA_Node *)&entry->node)->nodeClass==UA_NODECLASS_VARIABLE){ //set namespaceIndex in browseName in case id is generated ((UA_VariableNode*)&entry->node)->browseName.namespaceIndex=((UA_Node *)&entry->node)->nodeId.namespaceIndex; } unsigned long identifier; long before, after; rcu_read_lock(); cds_lfht_count_nodes(ns->ht, &before, &identifier, &after); // current amount of nodes stored identifier++; ((UA_Node *)&entry->node)->nodeId.identifier.numeric = identifier; while(UA_TRUE) { hash_t nhash = hash(&entry->node.nodeId); result = cds_lfht_add_unique(ns->ht, nhash, compare, &entry->node.nodeId, &entry->htn); if(result == &entry->htn) break; ((UA_Node *)&entry->node)->nodeId.identifier.numeric += (identifier * 2654435761); } rcu_read_unlock(); } UA_NodeId_deleteMembers(&tempNodeid); UA_free(node); if(inserted) *inserted = &entry->node; return UA_STATUSCODE_GOOD; }
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; }