static void setup_lds(void) { // start LDS server running_lds = UA_Boolean_new(); *running_lds = true; config_lds = UA_ServerConfig_new_default(); config_lds->applicationDescription.applicationType = UA_APPLICATIONTYPE_DISCOVERYSERVER; UA_String_deleteMembers(&config_lds->applicationDescription.applicationUri); config_lds->applicationDescription.applicationUri = UA_STRING_ALLOC("urn:open62541.test.local_discovery_server"); UA_LocalizedText_deleteMembers(&config_lds->applicationDescription.applicationName); config_lds->applicationDescription.applicationName = UA_LOCALIZEDTEXT_ALLOC("en", "LDS Server"); config_lds->mdnsServerName = UA_String_fromChars("LDS_test"); config_lds->serverCapabilitiesSize = 1; UA_String *caps = UA_String_new(); *caps = UA_String_fromChars("LDS"); config_lds->serverCapabilities = caps; config_lds->discoveryCleanupTimeout = registerTimeout; server_lds = UA_Server_new(config_lds); UA_Server_run_startup(server_lds); pthread_create(&server_thread_lds, NULL, serverloop_lds, NULL); // wait until LDS started UA_sleep(1000); sleep(1); }
static void GetEndpointsAndCheck(const char* discoveryUrl, const char* filterTransportProfileUri, const UA_String expectedEndpointUrls[], size_t expectedEndpointUrlsSize) { UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); ck_assert_uint_eq(UA_Client_connect(client, discoveryUrl), UA_STATUSCODE_GOOD); UA_EndpointDescription* endpointArray = NULL; size_t endpointArraySize = 0; UA_String discoveryUrlUA = UA_String_fromChars(discoveryUrl); UA_StatusCode retval = GetEndpoints(client, &discoveryUrlUA, &endpointArraySize, &endpointArray, filterTransportProfileUri); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_String_deleteMembers(&discoveryUrlUA); ck_assert_uint_eq(endpointArraySize , expectedEndpointUrlsSize); for(size_t j = 0; j < endpointArraySize && j < expectedEndpointUrlsSize; j++) { UA_EndpointDescription* endpoint = &endpointArray[j]; ck_assert(UA_String_equal(&endpoint->endpointUrl, &expectedEndpointUrls[j])); } UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); UA_Client_delete(client); }
static void setup_register(void) { // start register server running_register = UA_Boolean_new(); *running_register = true; config_register = UA_ServerConfig_new_minimal(16664, NULL); UA_String_deleteMembers(&config_register->applicationDescription.applicationUri); config_register->applicationDescription.applicationUri = UA_String_fromChars("urn:open62541.test.server_register"); UA_LocalizedText_deleteMembers(&config_register->applicationDescription.applicationName); config_register->applicationDescription.applicationName = UA_LOCALIZEDTEXT_ALLOC("de", "Anmeldungsserver"); config_register->mdnsServerName = UA_String_fromChars("Register_test"); server_register = UA_Server_new(config_register); UA_Server_run_startup(server_register); pthread_create(&server_thread_register, NULL, serverloop_register, NULL); }
static void FindOnNetworkAndCheck(UA_String expectedServerNames[], size_t expectedServerNamesSize, const char *filterUri, const char *filterLocale, const char** filterCapabilities, size_t filterCapabilitiesSize) { UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); UA_ServerOnNetwork* serverOnNetwork = NULL; size_t serverOnNetworkSize = 0; size_t serverCapabilityFilterSize = 0; UA_String *serverCapabilityFilter = NULL; if(filterCapabilitiesSize) { serverCapabilityFilterSize = filterCapabilitiesSize; serverCapabilityFilter = (UA_String*)UA_malloc(sizeof(UA_String) * filterCapabilitiesSize); for(size_t i = 0; i < filterCapabilitiesSize; i++) serverCapabilityFilter[i] = UA_String_fromChars(filterCapabilities[i]); } UA_StatusCode retval = UA_Client_findServersOnNetwork(client, "opc.tcp://localhost:4840", 0, 0, serverCapabilityFilterSize, serverCapabilityFilter, &serverOnNetworkSize, &serverOnNetwork); if(serverCapabilityFilterSize) UA_Array_delete(serverCapabilityFilter, serverCapabilityFilterSize, &UA_TYPES[UA_TYPES_STRING]); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); // only the discovery server is expected ck_assert_uint_eq(serverOnNetworkSize , expectedServerNamesSize); if(expectedServerNamesSize > 0) ck_assert_ptr_ne(serverOnNetwork, NULL); if(serverOnNetwork != NULL) { for(size_t i = 0; i < expectedServerNamesSize; i++) { UA_Boolean expectedServerNameInServerOnNetwork = false; for(size_t j = 0; j < expectedServerNamesSize && !expectedServerNameInServerOnNetwork; j++) { expectedServerNameInServerOnNetwork = UA_String_equal(&serverOnNetwork[j].serverName, &expectedServerNames[i]); } ck_assert_msg(expectedServerNameInServerOnNetwork, "Expected %.*s in serverOnNetwork list, but not found", expectedServerNames[i].length, expectedServerNames[i].data); } } UA_Array_delete(serverOnNetwork, serverOnNetworkSize, &UA_TYPES[UA_TYPES_SERVERONNETWORK]); UA_Client_disconnect(client); UA_Client_delete(client); }
static void setup_server(void) { // start server running_translate_browse = UA_Boolean_new(); *running_translate_browse = true; server_translate_config = UA_ServerConfig_new_default(); UA_String_deleteMembers(&server_translate_config->applicationDescription.applicationUri); server_translate_config->applicationDescription.applicationUri = UA_String_fromChars("urn:open62541.test.server_translate_browse"); server_translate_browse = UA_Server_new(server_translate_config); UA_Server_run_startup(server_translate_browse); pthread_create(&server_thread_translate_browse, NULL, serverloop_register, NULL); }
static void setup_register(void) { // start register server running_register = UA_Boolean_new(); *running_register = true; server_register = UA_Server_new(); UA_ServerConfig *config_register = UA_Server_getConfig(server_register); UA_ServerConfig_setMinimal(config_register, 16664, NULL); UA_String_deleteMembers(&config_register->applicationDescription.applicationUri); config_register->applicationDescription.applicationUri = UA_String_fromChars("urn:open62541.test.server_register"); UA_LocalizedText_deleteMembers(&config_register->applicationDescription.applicationName); config_register->applicationDescription.applicationName = UA_LOCALIZEDTEXT_ALLOC("de", "Anmeldungsserver"); #ifdef UA_ENABLE_DISCOVERY_MULTICAST config_register->discovery.mdns.mdnsServerName = UA_String_fromChars("Register_test"); #endif UA_Server_run_startup(server_register); THREAD_CREATE(server_thread_register, serverloop_register); }
static void configure_lds_server(UA_Server *pServer) { UA_ServerConfig *config_lds = UA_Server_getConfig(pServer); UA_ServerConfig_setDefault(config_lds); config_lds->applicationDescription.applicationType = UA_APPLICATIONTYPE_DISCOVERYSERVER; UA_String_deleteMembers(&config_lds->applicationDescription.applicationUri); config_lds->applicationDescription.applicationUri = UA_STRING_ALLOC("urn:open62541.test.local_discovery_server"); UA_LocalizedText_deleteMembers(&config_lds->applicationDescription.applicationName); config_lds->applicationDescription.applicationName = UA_LOCALIZEDTEXT_ALLOC("en", "LDS Server"); config_lds->discovery.mdnsEnable = true; #ifdef UA_ENABLE_DISCOVERY_MULTICAST config_lds->discovery.mdns.mdnsServerName = UA_String_fromChars("LDS_test"); config_lds->discovery.mdns.serverCapabilitiesSize = 1; UA_String *caps = UA_String_new(); *caps = UA_String_fromChars("LDS"); config_lds->discovery.mdns.serverCapabilities = caps; #endif config_lds->discovery.cleanupTimeout = registerTimeout; }
static UA_StatusCode GetEndpoints(UA_Client *client, const UA_String* endpointUrl, size_t* endpointDescriptionsSize, UA_EndpointDescription** endpointDescriptions, const char* filterTransportProfileUri) { UA_GetEndpointsRequest request; UA_GetEndpointsRequest_init(&request); //request.requestHeader.authenticationToken = client->authenticationToken; request.requestHeader.timestamp = UA_DateTime_now(); request.requestHeader.timeoutHint = 10000; request.endpointUrl = *endpointUrl; // assume the endpointurl outlives the service call if (filterTransportProfileUri) { request.profileUrisSize = 1; request.profileUris = (UA_String*)UA_malloc(sizeof(UA_String)); request.profileUris[0] = UA_String_fromChars(filterTransportProfileUri); } UA_GetEndpointsResponse response; UA_GetEndpointsResponse_init(&response); __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]); if (filterTransportProfileUri) { UA_Array_delete(request.profileUris, request.profileUrisSize, &UA_TYPES[UA_TYPES_STRING]); } ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD); *endpointDescriptionsSize = response.endpointsSize; *endpointDescriptions = (UA_EndpointDescription*)UA_Array_new(response.endpointsSize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); for(size_t i=0;i<response.endpointsSize;i++) { UA_EndpointDescription_init(&(*endpointDescriptions)[i]); UA_EndpointDescription_copy(&response.endpoints[i], &(*endpointDescriptions)[i]); } UA_GetEndpointsResponse_deleteMembers(&response); return UA_STATUSCODE_GOOD; }
int main(void) { signal(SIGINT, stopHandler); signal(SIGTERM, stopHandler); UA_ServerConfig config = UA_ServerConfig_standard; config.applicationDescription.applicationType = UA_APPLICATIONTYPE_DISCOVERYSERVER; config.applicationDescription.applicationUri = UA_String_fromChars("open62541.example.local_discovery_server"); // timeout in seconds when to automatically remove a registered server from the list, // if it doesn't re-register within the given time frame. A value of 0 disables automatic removal. // Default is 60 Minutes (60*60). Must be bigger than 10 seconds, because cleanup is only triggered approximately // ervery 10 seconds. // The server will still be removed depending on the state of the semaphore file. // config.discoveryCleanupTimeout = 60*60; UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 4840); config.networkLayers = &nl; config.networkLayersSize = 1; UA_Server *server = UA_Server_new(config); UA_StatusCode retval = UA_Server_run(server, &running); UA_String_deleteMembers(&config.applicationDescription.applicationUri); UA_Server_delete(server); nl.deleteMembers(&nl); return (int)retval; }
OV_DLLFNCEXPORT UA_StatusCode servicesOPCUAInterface_interface_ovServiceOutputArgumentsNodeToOPCUA( 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_STRING tmpString = NULL; OV_UINT len = 0; OV_STRING *plist = NULL; copyOPCUAStringToOV(nodeId->identifier.string, &tmpString); plist = ov_string_split(tmpString, "||", &len); ov_string_setvalue(&tmpString, NULL); UA_NodeId tmpNodeId; UA_NodeId_init(&tmpNodeId); tmpNodeId.namespaceIndex = nodeId->namespaceIndex; tmpNodeId.identifierType = nodeId->identifierType; tmpNodeId.identifier.string = UA_String_fromChars(plist[0]); ov_string_freelist(plist); ov_memstack_lock(); result = opcua_nodeStoreFunctions_resolveNodeIdToPath(tmpNodeId, &path); UA_NodeId_deleteMembers(&tmpNodeId); 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("OutputArguments"); qName.namespaceIndex = 0; //pinterface->v_interfacenamespace.index; newNode->browseName = qName; // 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("OutputArguments"); 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 // value OV_ELEMENT tmpPart; tmpPart.elemtype = OV_ET_NONE; tmpPart.pobj = NULL; OV_ELEMENT tmpParrent; tmpParrent.pobj = pobj; tmpParrent.elemtype = OV_ET_OBJECT; OV_UINT sizeOutput = 0; do { ov_element_getnextpart(&tmpParrent, &tmpPart, OV_ET_VARIABLE); if (tmpPart.elemtype == OV_ET_NONE) break; if (tmpPart.elemunion.pvar->v_flags == 16384){ // OutputFlag is set sizeOutput++; continue; } } while(TRUE); // arrayDemensions if (sizeOutput > 1){ ((UA_VariableNode*)newNode)->arrayDimensionsSize = 1; UA_UInt32 *pOutputDimension = UA_UInt32_new(); *pOutputDimension = sizeOutput; ((UA_VariableNode*)newNode)->arrayDimensions = pOutputDimension; //UA_Array_new(((UA_VariableNode*)newNode)->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]); /* scalar or one dimension */ // valuerank ((UA_VariableNode*)newNode)->valueRank = 1; /* one dimension */ }else{ ((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 ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->type = &UA_TYPES[UA_TYPES_ARGUMENT]; ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->arrayLength = sizeOutput; if (sizeOutput > 1){ ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data = UA_Array_new(sizeOutput, &UA_TYPES[UA_TYPES_ARGUMENT]); }else{ ((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data = UA_Argument_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; tmpPart.elemtype = OV_ET_NONE; tmpPart.pobj = NULL; OV_UINT count = 0; do { ov_element_getnextpart(&tmpParrent, &tmpPart, OV_ET_VARIABLE); if (tmpPart.elemtype == OV_ET_NONE) break; if (tmpPart.elemunion.pvar->v_flags == 16384){ // OutputFlag is set UA_Argument_init(&((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count]); ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].description = UA_LOCALIZEDTEXT_ALLOC("en_US",""); ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].name = UA_STRING_ALLOC(tmpPart.elemunion.pvar->v_identifier); ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; switch(tmpPart.elemunion.pvar->v_vartype){ case OV_VT_BOOL: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_BOOLEAN].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_INT: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_INT32].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_UINT: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_UINT32].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_SINGLE: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_FLOAT].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_DOUBLE: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_ANY: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_VARIANT].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_STRING: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_STRING].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = -1; break; case OV_VT_BOOL_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_BOOLEAN].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_INT_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_INT32].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_UINT_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_UINT32].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_SINGLE_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_FLOAT].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_DOUBLE_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; case OV_VT_STRING_VEC: ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].dataType = UA_TYPES[UA_TYPES_STRING].typeId; ((UA_Argument*)((UA_Variant*)&((UA_VariableNode*)newNode)->value.data.value.value)->data)[count].valueRank = 1; break; default: break; } count++; if (count == sizeOutput){ break; }else{ continue; } } } while(TRUE); ov_string_setvalue(&tmpString, NULL); // 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(0, 0); // References have to do manual because it is an virtual node size_t size_references = 0; size_references = size_references + 2;// For Parent&TypeNode newNode->references = UA_calloc(size_references, sizeof(UA_ReferenceNode)); if (!newNode->references){ result = ov_resultToUaStatusCode(OV_ERR_HEAPOUTOFMEMORY); UA_free(newNode); return result; } newNode->referencesSize = size_references; // ParentNode newNode->references[0].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY); newNode->references[0].isInverse = UA_TRUE; len = 0; plist = NULL; tmpString = NULL; copyOPCUAStringToOV(nodeId->identifier.string, &tmpString); plist = ov_string_split(tmpString, "||", &len); newNode->references[0].targetId = UA_EXPANDEDNODEID_STRING_ALLOC(pinterface->v_interfacenamespace.index, plist[0]); ov_string_freelist(plist); ov_string_setvalue(&tmpString, NULL); // TypeNode newNode->references[1].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION); newNode->references[1].isInverse = UA_FALSE; newNode->references[1].targetId = UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE); *opcuaNode = newNode; return UA_STATUSCODE_GOOD; }
END_TEST static void FindAndCheck(const UA_String expectedUris[], size_t expectedUrisSize, const UA_String expectedLocales[], const UA_String expectedNames[], const char *filterUri, const char *filterLocale) { UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); UA_ApplicationDescription* applicationDescriptionArray = NULL; size_t applicationDescriptionArraySize = 0; size_t serverUrisSize = 0; UA_String *serverUris = NULL; if(filterUri) { serverUrisSize = 1; serverUris = UA_String_new(); serverUris[0] = UA_String_fromChars(filterUri); } size_t localeIdsSize = 0; UA_String *localeIds = NULL; if(filterLocale) { localeIdsSize = 1; localeIds = UA_String_new(); localeIds[0] = UA_String_fromChars(filterLocale); } UA_StatusCode retval = UA_Client_findServers(client, "opc.tcp://localhost:4840", serverUrisSize, serverUris, localeIdsSize, localeIds, &applicationDescriptionArraySize, &applicationDescriptionArray); if(filterUri) UA_Array_delete(serverUris, serverUrisSize, &UA_TYPES[UA_TYPES_STRING]); if(filterLocale) UA_Array_delete(localeIds, localeIdsSize, &UA_TYPES[UA_TYPES_STRING]); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); // only the discovery server is expected ck_assert_uint_eq(applicationDescriptionArraySize, expectedUrisSize); ck_assert(applicationDescriptionArray != NULL); for(size_t i = 0; i < expectedUrisSize; ++i) { ck_assert(UA_String_equal(&applicationDescriptionArray[i].applicationUri, &expectedUris[i])); if(expectedNames) ck_assert(UA_String_equal(&applicationDescriptionArray[i].applicationName.text, &expectedNames[i])); if (expectedLocales) ck_assert(UA_String_equal(&applicationDescriptionArray[i].applicationName.locale, &expectedLocales[i])); } UA_Array_delete(applicationDescriptionArray, applicationDescriptionArraySize, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]); UA_Client_disconnect(client); UA_Client_delete(client); }
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; }
OV_DLLFNCEXPORT OV_RESULT opcuafb_Write_Execute_set( OV_INSTPTR_opcuafb_Write pinst, const OV_BOOL value ) { OV_INSTPTR_opcuafb_Connect pConnect = NULL; OV_INSTPTR_opcuafb_NodeGetHandle pNodeGetHandle = NULL; UA_WriteRequest WriteRequest; UA_WriteResponse WriteResponse; UA_String tempString; UA_DateTime *tempTime; char *endPtr = NULL; unsigned long int tempulong = 0; if(value == FALSE || pinst->v_Execute == TRUE){ //only react on the rising edge pinst->v_Execute = value; return OV_ERR_OK; } pConnect = Ov_DynamicPtrCast(opcuafb_Connect, fb_connection_getFirstConnectedObject(Ov_PtrUpCast(fb_object, pinst), FALSE, TRUE, "ConnectionHdl")); if(pConnect == NULL){ pinst->v_Error = TRUE; pinst->v_ErrorID = 1; //todo return OV_ERR_BADVALUE; } if(pConnect->v_ConnectionHdl == 0){ pinst->v_Error = TRUE; pinst->v_ErrorID = 1; //todo return OV_ERR_BADVALUE; } if(pConnect->v_Client == NULL){ //internal error pinst->v_Error = TRUE; pinst->v_ErrorID = 1; //todo return OV_ERR_BADVALUE; } pNodeGetHandle = Ov_DynamicPtrCast(opcuafb_NodeGetHandle, fb_connection_getFirstConnectedObject(Ov_PtrUpCast(fb_object, pinst), FALSE, TRUE, "NodeHdl")); if(pNodeGetHandle == NULL){ pinst->v_Error = TRUE; pinst->v_ErrorID = 1; //todo return OV_ERR_BADVALUE; } if(pNodeGetHandle->v_NodeHdl == 0){ pinst->v_Error = TRUE; pinst->v_ErrorID = 1; //todo return OV_ERR_BADVALUE; } UA_WriteRequest_init(&WriteRequest); WriteRequest.nodesToWrite = UA_WriteValue_new(); WriteRequest.nodesToWriteSize = 1; WriteRequest.nodesToWrite[0].attributeId = UA_ATTRIBUTEID_VALUE; WriteRequest.nodesToWrite[0].value.hasValue = UA_TRUE; if(pNodeGetHandle->v_NodeID.IdentifierType == UA_IDTYPE_STRING){ WriteRequest.nodesToWrite[0].nodeId = UA_NODEID_STRING_ALLOC(pNodeGetHandle->v_NodeID.NamespaceIndex, pNodeGetHandle->v_NodeID.Identifier); }else if(pNodeGetHandle->v_NodeID.IdentifierType == UA_IDTYPE_NUMERIC){ tempulong = strtoul(pNodeGetHandle->v_NodeID.Identifier, &endPtr, 10); if (ERANGE != errno && tempulong < UINT16_MAX && endPtr != pNodeGetHandle->v_NodeID.Identifier) { WriteRequest.nodesToWrite[0].nodeId = UA_NODEID_NUMERIC(pNodeGetHandle->v_NodeID.NamespaceIndex, (UA_UInt16)tempulong); } WriteRequest.nodesToWrite[0].nodeId = UA_NODEID_NUMERIC(pNodeGetHandle->v_NodeID.NamespaceIndex, atoi(pNodeGetHandle->v_NodeID.Identifier)); // }else if(pNodeGetHandle->v_NodeID.IdentifierType == UA_IDTYPE_GUID){ //todo //WriteRequest.nodesToWrite[0].nodeId = UA_NODEID_GUID(pNodeGetHandle->v_NodeID.NamespaceIndex, pNodeGetHandle->v_NodeID.Identifier); }else{ UA_WriteRequest_deleteMembers(&WriteRequest); return OV_ERR_BADVALUE; } switch (pinst->v_Variable.value.vartype & OV_VT_KSMASK){ case OV_VT_INT: WriteRequest.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT32]; WriteRequest.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; //do not free the data on deletion WriteRequest.nodesToWrite[0].value.value.data = &pinst->v_Variable.value.valueunion.val_int; break; case OV_VT_UINT: WriteRequest.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_UINT32]; WriteRequest.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; //do not free the data on deletion WriteRequest.nodesToWrite[0].value.value.data = &pinst->v_Variable.value.valueunion.val_uint; break; case OV_VT_SINGLE: WriteRequest.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_FLOAT]; WriteRequest.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; //do not free the data on deletion WriteRequest.nodesToWrite[0].value.value.data = &pinst->v_Variable.value.valueunion.val_single; break; case OV_VT_DOUBLE: WriteRequest.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_DOUBLE]; WriteRequest.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; //do not free the data on deletion WriteRequest.nodesToWrite[0].value.value.data = &pinst->v_Variable.value.valueunion.val_double; break; case OV_VT_STRING: WriteRequest.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_STRING]; WriteRequest.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA; //free the data on deletion WriteRequest.nodesToWrite[0].value.value.data = UA_String_new(); tempString = UA_String_fromChars(pinst->v_Variable.value.valueunion.val_string); WriteRequest.nodesToWrite[0].value.value.data = &tempString; break; case OV_VT_TIME: WriteRequest.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_DATETIME]; WriteRequest.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA; //free the data on deletion tempTime = UA_DateTime_new(); if(tempTime){ *tempTime = ov_ovTimeTo1601nsTime(pinst->v_Variable.value.valueunion.val_time); WriteRequest.nodesToWrite[0].value.value.data = tempTime; }else{ pinst->v_Error = TRUE; pinst->v_ErrorID = 1; // todo } break; default: break; } WriteResponse = UA_Client_Service_write(pConnect->v_Client, WriteRequest); if(WriteResponse.responseHeader.serviceResult != UA_STATUSCODE_GOOD){ pinst->v_Error = FALSE; pinst->v_ErrorID = 0; }else{ pinst->v_Error = TRUE; pinst->v_ErrorID = 1; // todo } UA_WriteResponse_deleteMembers(&WriteResponse); UA_WriteRequest_deleteMembers(&WriteRequest); pinst->v_Done = TRUE; pinst->v_Execute = value; return OV_ERR_OK; }
int main(int argc, char **argv) { signal(SIGINT, stopHandler); /* catches ctrl-c */ signal(SIGTERM, stopHandler); UA_ServerConfig *config = UA_ServerConfig_new_default(); UA_String_deleteMembers(&config->applicationDescription.applicationUri); config->applicationDescription.applicationUri = UA_String_fromChars("urn:open62541.example.server_register"); config->mdnsServerName = UA_String_fromChars("Sample Server"); // See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv //config.serverCapabilitiesSize = 1; //UA_String caps = UA_String_fromChars("LDS"); //config.serverCapabilities = ∩︀ UA_Server *server = UA_Server_new(config); /* add a variable node to the address space */ UA_Int32 myInteger = 42; UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer"); UA_DataSource dateDataSource; dateDataSource.read = readInteger; dateDataSource.write = writeInteger; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "the answer"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "the answer"); UA_Server_addDataSourceVariableNode(server, myIntegerNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), myIntegerName, UA_NODEID_NULL, attr, dateDataSource, &myInteger, NULL); // periodic server register after 10 Minutes, delay first register for 500ms UA_StatusCode retval = UA_Server_addPeriodicServerRegisterCallback(server, DISCOVERY_SERVER_ENDPOINT, 10 * 60 * 1000, 500, NULL); // UA_StatusCode retval = UA_Server_addPeriodicServerRegisterJob(server, // "opc.tcp://localhost:4840", 10*60*1000, 500, NULL); if (retval != UA_STATUSCODE_GOOD) { UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not create periodic job for server register. StatusCode %s", UA_StatusCode_name(retval)); UA_Server_delete(server); UA_ServerConfig_delete(config); return (int)retval; } retval = UA_Server_run(server, &running); if (retval != UA_STATUSCODE_GOOD) { UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not start the server. StatusCode %s", UA_StatusCode_name(retval)); UA_Server_delete(server); UA_ServerConfig_delete(config); return (int)retval; } // UNregister the server from the discovery server. retval = UA_Server_unregister_discovery(server, DISCOVERY_SERVER_ENDPOINT); //retval = UA_Server_unregister_discovery(server, "opc.tcp://localhost:4840" ); if(retval != UA_STATUSCODE_GOOD) UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not unregister server from discovery server. StatusCode %s", UA_StatusCode_name(retval)); UA_Server_delete(server); UA_ServerConfig_delete(config); return (int)retval; }
int main(int argc, char **argv) { signal(SIGINT, stopHandler); /* catches ctrl-c */ signal(SIGTERM, stopHandler); UA_ServerConfig *config = UA_ServerConfig_new_minimal(16600, NULL); // To enable mDNS discovery, set application type to discovery server. config->applicationDescription.applicationType = UA_APPLICATIONTYPE_DISCOVERYSERVER; UA_String_deleteMembers(&config->applicationDescription.applicationUri); config->applicationDescription.applicationUri = UA_String_fromChars("urn:open62541.example.server_multicast"); config->mdnsServerName = UA_String_fromChars("Sample Multicast Server"); // See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv //config.serverCapabilitiesSize = 1; //UA_String caps = UA_String_fromChars("LDS"); //config.serverCapabilities = ∩︀ UA_Server *server = UA_Server_new(config); self_discovery_url = &config->networkLayers[0].discoveryUrl; /* add a variable node to the address space */ UA_Int32 myInteger = 42; UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer"); UA_DataSource dateDataSource; dateDataSource.read = readInteger; dateDataSource.write = writeInteger; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "the answer"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "the answer"); UA_Server_addDataSourceVariableNode(server, myIntegerNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), myIntegerName, UA_NODEID_NULL, attr, dateDataSource, &myInteger, NULL); // callback which is called when a new server is detected through mDNS UA_Server_setServerOnNetworkCallback(server, serverOnNetworkCallback, NULL); // Start the server and call iterate to wait for the multicast discovery of the LDS UA_StatusCode retval = UA_Server_run_startup(server); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not start the server. StatusCode %s", UA_StatusCode_name(retval)); UA_Server_delete(server); UA_ServerConfig_delete(config); UA_free(discovery_url); return 1; } UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "Server started. Waiting for announce of LDS Server."); while (running && discovery_url == NULL) UA_Server_run_iterate(server, true); if(!running) { UA_Server_delete(server); UA_ServerConfig_delete(config); UA_free(discovery_url); return 1; } UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "LDS-ME server found on %s", discovery_url); /* Check if the server supports sign and encrypt. OPC Foundation LDS requires an encrypted session for * RegisterServer call, our server currently uses encrpytion optionally */ UA_EndpointDescription *endpointRegister = getRegisterEndpointFromServer(discovery_url); UA_free(discovery_url); if (endpointRegister == NULL || endpointRegister->securityMode == UA_MESSAGESECURITYMODE_INVALID) { UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not find any suitable endpoints on discovery server"); UA_Server_delete(server); UA_ServerConfig_delete(config); return 1; } UA_Client *clientRegister = getRegisterClient(endpointRegister, argc, argv); if (!clientRegister) { UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Could not create the client for remote registering"); UA_Server_delete(server); UA_ServerConfig_delete(config); return 1; } /* Connect the client */ char *endpointUrl = (char*)UA_malloc(endpointRegister->endpointUrl.length + 1); memcpy(endpointUrl, endpointRegister->endpointUrl.data, endpointRegister->endpointUrl.length); endpointUrl[endpointRegister->endpointUrl.length] = 0; retval = UA_Server_addPeriodicServerRegisterCallback(server, clientRegister, endpointUrl, 10 * 60 * 1000, 500, NULL); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not create periodic job for server register. StatusCode %s", UA_StatusCode_name(retval)); UA_free(endpointUrl); UA_Client_disconnect(clientRegister); UA_Client_delete(clientRegister); UA_Server_delete(server); UA_ServerConfig_delete(config); return 1; } while (running) UA_Server_run_iterate(server, true); UA_Server_run_shutdown(server); // UNregister the server from the discovery server. retval = UA_Server_unregister_discovery(server, clientRegister); if (retval != UA_STATUSCODE_GOOD) UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not unregister server from discovery server. " "StatusCode %s", UA_StatusCode_name(retval)); UA_free(endpointUrl); UA_Client_disconnect(clientRegister); UA_Client_delete(clientRegister); UA_Server_delete(server); UA_ServerConfig_delete(config); return (int)retval; }