END_TEST // Test if registered server is returned from LDS using FindServersOnNetwork START_TEST(Client_find_on_network_registered) { char urls[2][64]; UA_String expectedUris[2]; char hostname[256]; ck_assert_uint_eq(gethostname(hostname, 255), 0); //DNS limits name to max 63 chars (+ \0) //We need this ugly casting, otherwise gcc >7.2 will complain about format-truncation, but we want it here void *hostnameVoid = (void*)hostname; snprintf(urls[0], 64, "LDS_test-%s", (char*)hostnameVoid); snprintf(urls[1], 64, "Register_test-%s", (char*)hostnameVoid); expectedUris[0] = UA_STRING(urls[0]); expectedUris[1] = UA_STRING(urls[1]); FindOnNetworkAndCheck(expectedUris, 2, NULL, NULL, NULL, 0); // filter by Capabilities const char* capsLDS[] = {"LDS"}; const char* capsNA[] = {"NA"}; const char* capsMultiple[] = {"LDS", "NA"}; // only LDS expected FindOnNetworkAndCheck(expectedUris, 1, NULL, NULL, capsLDS, 1); // only register server expected FindOnNetworkAndCheck(&expectedUris[1], 1, NULL, NULL, capsNA, 1); // no server expected FindOnNetworkAndCheck(NULL, 0, NULL, NULL, capsMultiple, 2); }
static UA_NodeId addPubSubConnection(void){ UA_Variant publisherId; UA_Variant_init(&publisherId); UA_UInt32 publisherIdValue = 13245; UA_Variant_setScalar(&publisherId, &publisherIdValue , &UA_TYPES[UA_TYPES_UINT32]); UA_PubSubConnectionDataType pubSubConnection; UA_PubSubConnectionDataType_init(&pubSubConnection); pubSubConnection.name = UA_STRING("Model Connection 1"); pubSubConnection.enabled = UA_TRUE; pubSubConnection.publisherId = publisherId; pubSubConnection.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); UA_ExtensionObject eo; UA_NetworkAddressUrlDataType networkAddressDataType = {UA_STRING("eth0"), UA_STRING("opc.udp://224.0.0.22:4840/")}; UA_NetworkAddressUrlDataType* identityToken = UA_NetworkAddressUrlDataType_new(); UA_NetworkAddressUrlDataType_init(identityToken); UA_NetworkAddressUrlDataType_copy(&networkAddressDataType, identityToken); eo.encoding = UA_EXTENSIONOBJECT_DECODED; eo.content.decoded.type = &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]; eo.content.decoded.data = identityToken; pubSubConnection.address = eo; pubSubConnection.connectionPropertiesSize = 2; UA_KeyValuePair connectionOptions[2]; memset(connectionOptions, 0, sizeof(UA_KeyValuePair)* 2); connectionOptions[0].key = UA_QUALIFIEDNAME(0, "ttl"); UA_UInt32 ttl = 10; UA_Variant_setScalar(&connectionOptions[0].value, &ttl, &UA_TYPES[UA_TYPES_UINT32]); connectionOptions[1].key = UA_QUALIFIEDNAME(0, "loopback"); UA_Boolean loopback = UA_FALSE; UA_Variant_setScalar(&connectionOptions[1].value, &loopback, &UA_TYPES[UA_TYPES_UINT32]); pubSubConnection.connectionProperties = connectionOptions; UA_Variant inputArguments; UA_Variant_init(&inputArguments); UA_Variant_setScalar(&inputArguments, &pubSubConnection, &UA_TYPES[UA_TYPES_PUBSUBCONNECTIONDATATYPE]); UA_CallMethodRequest callMethodRequest; UA_CallMethodRequest_init(&callMethodRequest); callMethodRequest.inputArgumentsSize = 1; callMethodRequest.inputArguments = &inputArguments; callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE); callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION); UA_NodeId connectionId = UA_NODEID_NULL; UA_CallMethodResult result; UA_CallMethodResult_init(&result); result = UA_Server_call(server, &callMethodRequest); ck_assert_int_eq(1, result.outputArgumentsSize); ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD); if(result.outputArguments->type == &UA_TYPES[UA_TYPES_NODEID]) connectionId = *((UA_NodeId *) result.outputArguments->data); UA_ExtensionObject_deleteMembers(&eo); callMethodRequest.inputArguments = NULL; callMethodRequest.inputArgumentsSize = 0; UA_CallMethodRequest_deleteMembers(&callMethodRequest); UA_CallMethodResult_deleteMembers(&result); return connectionId; }
END_TEST // Test if registered server is returned from LDS using FindServersOnNetwork START_TEST(Client_find_on_network_registered) { char urls[2][64]; UA_String expectedUris[2]; char hostname[256]; ck_assert_uint_eq(gethostname(hostname, 255), 0); //DNS limits name to max 63 chars (+ \0) snprintf(urls[0], 64, "LDS_test-%s", hostname); snprintf(urls[1], 64, "Register_test-%s", hostname); expectedUris[0] = UA_STRING(urls[0]); expectedUris[1] = UA_STRING(urls[1]); FindOnNetworkAndCheck(expectedUris, 2, NULL, NULL, NULL, 0); // filter by Capabilities const char* capsLDS[] = {"LDS"}; const char* capsNA[] = {"NA"}; const char* capsMultiple[] = {"LDS", "NA"}; // only LDS expected FindOnNetworkAndCheck(expectedUris, 1, NULL, NULL, capsLDS, 1); // only register server expected FindOnNetworkAndCheck(&expectedUris[1], 1, NULL, NULL, capsNA, 1); // no server expected FindOnNetworkAndCheck(NULL, 0, NULL, NULL, capsMultiple, 2); }
int main(int argc, char **argv) { signal(SIGINT, stopHandler); signal(SIGTERM, stopHandler); UA_PubSubTransportLayer udpLayer = UA_PubSubTransportLayerUDPMP(); UA_PubSubConnectionConfig connectionConfig; memset(&connectionConfig, 0, sizeof(connectionConfig)); connectionConfig.name = UA_STRING("UADP Connection 1"); connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); connectionConfig.enabled = UA_TRUE; UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")}; UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); UA_PubSubChannel *psc = udpLayer.createPubSubChannel(&connectionConfig); psc->regist(psc, NULL, NULL); UA_StatusCode retval = UA_STATUSCODE_GOOD; while(running && retval == UA_STATUSCODE_GOOD) retval = subscriberListen(psc); psc->close(psc); return 0; }
} END_TEST START_TEST(AddSingleConnectionWithMaximalConfiguration){ UA_NetworkAddressUrlDataType networkAddressUrlData = {UA_STRING("127.0.0.1"), UA_STRING("opc.udp://224.0.0.22:4840/")}; UA_Variant address; UA_Variant_setScalar(&address, &networkAddressUrlData, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); UA_KeyValuePair connectionOptions[3]; connectionOptions[0].key = UA_QUALIFIEDNAME(0, "ttl"); UA_UInt32 ttl = 10; UA_Variant_setScalar(&connectionOptions[0].value, &ttl, &UA_TYPES[UA_TYPES_UINT32]); connectionOptions[1].key = UA_QUALIFIEDNAME(0, "loopback"); UA_Boolean loopback = UA_FALSE; UA_Variant_setScalar(&connectionOptions[1].value, &loopback, &UA_TYPES[UA_TYPES_UINT32]); connectionOptions[2].key = UA_QUALIFIEDNAME(0, "reuse"); UA_Boolean reuse = UA_TRUE; UA_Variant_setScalar(&connectionOptions[2].value, &reuse, &UA_TYPES[UA_TYPES_UINT32]); UA_PubSubConnectionConfig connectionConf; memset(&connectionConf, 0, sizeof(UA_PubSubConnectionConfig)); connectionConf.name = UA_STRING("UADP Connection"); connectionConf.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); connectionConf.enabled = true; connectionConf.publisherId.numeric = 223344; connectionConf.connectionPropertiesSize = 3; connectionConf.connectionProperties = connectionOptions; connectionConf.address = address; UA_NodeId connection; UA_StatusCode retVal = UA_Server_addPubSubConnection(server, &connectionConf, &connection); ck_assert_int_eq(server->pubSubManager.connectionsSize, 1); ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); ck_assert(server->pubSubManager.connections[0].channel != NULL); } END_TEST
END_TEST // Test if registered server is returned from LDS START_TEST(Client_find_registered) { UA_String expectedUris[2]; expectedUris[0] = UA_STRING("urn:open62541.test.local_discovery_server"); expectedUris[1] = UA_STRING("urn:open62541.test.server_register"); FindAndCheck(expectedUris, 2, NULL, NULL, NULL, NULL); }
} END_TEST START_TEST(AddAndRemovePublishedDataSetItems){ UA_StatusCode retVal; UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); retVal = UA_Client_connect(client, "opc.tcp://localhost:4840"); if(retVal != UA_STATUSCODE_GOOD) { UA_Client_delete(client); } ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_Variant *inputArguments = (UA_Variant *) UA_calloc(4, (sizeof(UA_Variant))); UA_String pdsName = UA_STRING("Test PDS"); UA_Variant_setScalar(&inputArguments[0], &pdsName, &UA_TYPES[UA_TYPES_STRING]); UA_String *fieldNameAliases = (UA_String *) UA_calloc(2, sizeof(UA_String)); fieldNameAliases[0] = UA_STRING("field1"); fieldNameAliases[1] = UA_STRING("field2"); UA_Variant_setArray(&inputArguments[1], fieldNameAliases, 2, &UA_TYPES[UA_TYPES_STRING]); UA_DataSetFieldFlags *dataSetFieldFlags = (UA_DataSetFieldFlags *) UA_calloc(2, sizeof(UA_DataSetFieldFlags)); dataSetFieldFlags[0] = UA_DATASETFIELDFLAGS_PROMOTEDFIELD; dataSetFieldFlags[1] = UA_DATASETFIELDFLAGS_PROMOTEDFIELD; UA_Variant_setArray(&inputArguments[2], dataSetFieldFlags, 2, &UA_TYPES[UA_TYPES_DATASETFIELDFLAGS]); UA_PublishedVariableDataType *variablesToAdd = (UA_PublishedVariableDataType *) UA_calloc(2, sizeof(UA_PublishedVariableDataType)); variablesToAdd[0].publishedVariable = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_LOCALTIME); variablesToAdd[0].attributeId = UA_ATTRIBUTEID_VALUE; variablesToAdd[1].publishedVariable = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_CURRENTSERVERID); variablesToAdd[1].attributeId = UA_ATTRIBUTEID_VALUE; UA_Variant_setArray(&inputArguments[3], variablesToAdd, 2, &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]); UA_CallMethodRequest callMethodRequest; UA_CallMethodRequest_init(&callMethodRequest); callMethodRequest.inputArgumentsSize = 4; callMethodRequest.inputArguments = inputArguments; callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS); callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS); UA_CallMethodResult result; UA_CallMethodResult_init(&result); result = UA_Server_call(server, &callMethodRequest); ck_assert_int_eq(3, result.outputArgumentsSize); ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD); //TODO checked correctness of created items UA_CallMethodResult_deleteMembers(&result); UA_free(inputArguments); UA_free(fieldNameAliases); UA_free(dataSetFieldFlags); UA_free(variablesToAdd); UA_Client_disconnect(client); UA_Client_delete(client); } END_TEST
int main(void) { signal(SIGINT, stopHandler); signal(SIGTERM, stopHandler); UA_ServerConfig *config = UA_ServerConfig_new_minimal(4801, NULL); /* Details about the PubSubTransportLayer can be found inside the * tutorial_pubsub_connection */ config->pubsubTransportLayers = (UA_PubSubTransportLayer *) UA_malloc(sizeof(UA_PubSubTransportLayer)); if (!config->pubsubTransportLayers) { UA_ServerConfig_delete(config); return -1; } config->pubsubTransportLayers[0] = UA_PubSubTransportLayerUDPMP(); config->pubsubTransportLayersSize++; UA_Server *server = UA_Server_new(config); UA_PubSubConnectionConfig connectionConfig; memset(&connectionConfig, 0, sizeof(connectionConfig)); connectionConfig.name = UA_STRING("UDP-UADP Connection 1"); connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); connectionConfig.enabled = UA_TRUE; UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")}; UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); UA_NodeId connectionIdent; UA_StatusCode retval = UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdent); if(retval == UA_STATUSCODE_GOOD) UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "The PubSub Connection was created successfully!"); /* The following lines register the listening on the configured multicast * address and configure a repeated job, which is used to handle received * messages. */ UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, connectionIdent); if(connection != NULL) { UA_StatusCode rv = connection->channel->regist(connection->channel, NULL); if (rv == UA_STATUSCODE_GOOD) { UA_UInt64 subscriptionCallbackId; UA_Server_addRepeatedCallback(server, (UA_ServerCallback)subscriptionPollingCallback, connection, 100, &subscriptionCallbackId); } else { UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "register channel failed: %s!", UA_StatusCode_name(rv)); } } retval |= UA_Server_run(server, &running); UA_Server_delete(server); UA_ServerConfig_delete(config); return (int)retval; }
} END_TEST START_TEST(AddAndRemoveWriterGroups){ UA_StatusCode retVal; UA_Client *client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); retVal = UA_Client_connect(client, "opc.tcp://localhost:4840"); if(retVal != UA_STATUSCODE_GOOD) { UA_Client_delete(client); } ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_NodeId createdConnection = addPubSubConnection(); UA_Variant *inputArgument = (UA_Variant *) UA_calloc(1, (sizeof(UA_Variant))); UA_WriterGroupDataType writerGroupDataType; UA_WriterGroupDataType_init(&writerGroupDataType); writerGroupDataType.name = UA_STRING("TestWriterGroup"); writerGroupDataType.enabled = UA_TRUE; writerGroupDataType.publishingInterval = 500; writerGroupDataType.writerGroupId = 1234; UA_Variant_setScalar(inputArgument, &writerGroupDataType, &UA_TYPES[UA_TYPES_WRITERGROUPDATATYPE]); UA_CallMethodRequest callMethodRequest; UA_CallMethodRequest_init(&callMethodRequest); callMethodRequest.inputArgumentsSize = 1; callMethodRequest.inputArguments = inputArgument; callMethodRequest.objectId = createdConnection; callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP); UA_CallMethodResult result; UA_CallMethodResult_init(&result); result = UA_Server_call(server, &callMethodRequest); ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD); ck_assert_int_eq(1, result.outputArgumentsSize); UA_NodeId createdWriterGroup = UA_NODEID_NULL; if(result.outputArguments->type == &UA_TYPES[UA_TYPES_NODEID]) createdWriterGroup = *((UA_NodeId *) result.outputArguments->data); UA_LocalizedText writerGroupDisplayName; UA_LocalizedText_init(&writerGroupDisplayName); retVal = UA_Server_readDisplayName(server, createdWriterGroup, &writerGroupDisplayName); ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_String compareText = UA_STRING("TestWriterGroup"); ck_assert(UA_String_equal(&writerGroupDisplayName.text, &compareText) == UA_TRUE); UA_free(inputArgument); UA_CallMethodResult_deleteMembers(&result); UA_Client_disconnect(client); UA_Client_delete(client); UA_LocalizedText_deleteMembers(&writerGroupDisplayName); } END_TEST
static UA_StatusCode EndpointsHandshake(UA_Client *client) { UA_GetEndpointsRequest request; UA_GetEndpointsRequest_init(&request); request.requestHeader.authenticationToken = client->authenticationToken; request.requestHeader.timestamp = UA_DateTime_now(); request.requestHeader.timeoutHint = 10000; request.endpointUrl = client->endpointUrl; UA_String profileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary"); request.profileUris = &profileUri; request.profileUrisSize = 1; UA_GetEndpointsResponse response; UA_GetEndpointsResponse_init(&response); __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]); UA_Boolean endpointFound = UA_FALSE; UA_Boolean tokenFound = UA_FALSE; UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); for(UA_Int32 i = 0; i < response.endpointsSize; i++) { UA_EndpointDescription* endpoint = &response.endpoints[i]; /* look out for an endpoint without security */ if(!UA_String_equal(&endpoint->securityPolicyUri, &securityNone)) continue; endpointFound = UA_TRUE; /* endpoint with no security found */ /* look for a user token policy with an anonymous token */ for(UA_Int32 j=0; j<endpoint->userIdentityTokensSize; ++j) { UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j]; if(userToken->tokenType != UA_USERTOKENTYPE_ANONYMOUS) continue; tokenFound = UA_TRUE; UA_UserTokenPolicy_copy(userToken, &client->token); break; } } UA_GetEndpointsResponse_deleteMembers(&response); if(!endpointFound) { UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No suitable endpoint found"); return UA_STATUSCODE_BADINTERNALERROR; } if(!tokenFound) { UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "No anonymous token found"); return UA_STATUSCODE_BADINTERNALERROR; } return response.responseHeader.serviceResult; }
static int run(UA_String *transportProfile, UA_NetworkAddressUrlDataType *networkAddressUrl) { signal(SIGINT, stopHandler); signal(SIGTERM, stopHandler); UA_Server *server = UA_Server_new(); UA_ServerConfig *config = UA_Server_getConfig(server); UA_ServerConfig_setMinimal(config, 4801, NULL); /* Details about the PubSubTransportLayer can be found inside the * tutorial_pubsub_connection */ config->pubsubTransportLayers = (UA_PubSubTransportLayer *) UA_calloc(2, sizeof(UA_PubSubTransportLayer)); if(!config->pubsubTransportLayers) { UA_Server_delete(server); return EXIT_FAILURE; } config->pubsubTransportLayers[0] = UA_PubSubTransportLayerUDPMP(); config->pubsubTransportLayersSize++; #ifdef UA_ENABLE_PUBSUB_ETH_UADP config->pubsubTransportLayers[1] = UA_PubSubTransportLayerEthernet(); config->pubsubTransportLayersSize++; #endif UA_PubSubConnectionConfig connectionConfig; memset(&connectionConfig, 0, sizeof(connectionConfig)); connectionConfig.name = UA_STRING("UADP Connection 1"); connectionConfig.transportProfileUri = *transportProfile; connectionConfig.enabled = UA_TRUE; UA_Variant_setScalar(&connectionConfig.address, networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); UA_NodeId connectionIdent; UA_StatusCode retval = UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdent); if(retval == UA_STATUSCODE_GOOD) UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "The PubSub Connection was created successfully!"); /* The following lines register the listening on the configured multicast * address and configure a repeated job, which is used to handle received * messages. */ UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, connectionIdent); if(connection != NULL) { UA_StatusCode rv = connection->channel->regist(connection->channel, NULL, NULL); if (rv == UA_STATUSCODE_GOOD) { UA_UInt64 subscriptionCallbackId; UA_Server_addRepeatedCallback(server, (UA_ServerCallback)subscriptionPollingCallback, connection, 100, &subscriptionCallbackId); } else { UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "register channel failed: %s!", UA_StatusCode_name(rv)); } } retval |= UA_Server_run(server, &running); UA_Server_delete(server); return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;; }
/** * Setting up an event * ^^^^^^^^^^^^^^^^^^^ * In order to set up the event, we can first use ``UA_Server_createEvent`` to give us a node representation of the event. * All we need for this is our `EventType`. Once we have our event node, which is saved internally as an `ObjectNode`, * we can define the attributes the event has the same way we would define the attributes of an object node. It is not * necessary to define the attributes `EventId`, `ReceiveTime`, `SourceNode` or `EventType` since these are set * automatically by the server. In this example, we will be setting the fields 'Message' and 'Severity' in addition * to `Time` which is needed to make the example UaExpert compliant. */ static UA_StatusCode setUpEvent(UA_Server *server, UA_NodeId *outId) { UA_StatusCode retval = UA_Server_createEvent(server, eventType, outId); if (retval != UA_STATUSCODE_GOOD) { UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "createEvent failed. StatusCode %s", UA_StatusCode_name(retval)); return retval; } /* Set the Event Attributes */ /* Setting the Time is required or else the event will not show up in UAExpert! */ UA_DateTime eventTime = UA_DateTime_now(); UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Time"), &eventTime, &UA_TYPES[UA_TYPES_DATETIME]); UA_UInt16 eventSeverity = 100; UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Severity"), &eventSeverity, &UA_TYPES[UA_TYPES_UINT16]); UA_LocalizedText eventMessage = UA_LOCALIZEDTEXT("en-US", "An event has been generated."); UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "Message"), &eventMessage, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); UA_String eventSourceName = UA_STRING("Server"); UA_Server_writeObjectProperty_scalar(server, *outId, UA_QUALIFIEDNAME(0, "SourceName"), &eventSourceName, &UA_TYPES[UA_TYPES_STRING]); return UA_STATUSCODE_GOOD; }
} END_TEST START_TEST(AddConnectionWithUnknownTransportURL){ UA_StatusCode retVal; UA_PubSubConnectionConfig connectionConfig; memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); connectionConfig.name = UA_STRING("UADP Connection"); UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL, UA_STRING("opc.udp://224.0.0.22:4840/")}; UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/unknown-udp-uadp"); UA_NodeId connectionIdent; retVal = UA_Server_addPubSubConnection(server, &connectionConfig, &connectionIdent); ck_assert_int_eq(server->pubSubManager.connectionsSize, 0); ck_assert_int_ne(retVal, UA_STATUSCODE_GOOD); } END_TEST
static void manuallyDefinePump(UA_Server *server) { UA_NodeId pumpId; /* get the nodeid assigned by the server */ UA_ObjectAttributes oAttr = UA_ObjectAttributes_default; oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump (Manual)"); UA_Server_addObjectNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Pump (Manual)"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), oAttr, NULL, &pumpId); UA_VariableAttributes mnAttr = UA_VariableAttributes_default; UA_String manufacturerName = UA_STRING("Pump King Ltd."); UA_Variant_setScalar(&mnAttr.value, &manufacturerName, &UA_TYPES[UA_TYPES_STRING]); mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName"); UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "ManufacturerName"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), mnAttr, NULL, NULL); UA_VariableAttributes modelAttr = UA_VariableAttributes_default; UA_String modelName = UA_STRING("Mega Pump 3000"); UA_Variant_setScalar(&modelAttr.value, &modelName, &UA_TYPES[UA_TYPES_STRING]); modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName"); UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "ModelName"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), modelAttr, NULL, NULL); UA_VariableAttributes statusAttr = UA_VariableAttributes_default; UA_Boolean status = true; UA_Variant_setScalar(&statusAttr.value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]); statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status"); UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "Status"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), statusAttr, NULL, NULL); UA_VariableAttributes rpmAttr = UA_VariableAttributes_default; UA_Double rpm = 50.0; UA_Variant_setScalar(&rpmAttr.value, &rpm, &UA_TYPES[UA_TYPES_DOUBLE]); rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM"); UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "MotorRPMs"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), rpmAttr, NULL, NULL); }
static UA_StatusCode getMonitoredItems(void *methodHandle, const UA_NodeId objectId, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output) { UA_String tmp = UA_STRING("Hello World"); UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]); return UA_STATUSCODE_GOOD; }
END_TEST // Test if filtering with uris works START_TEST(Client_find_filter) { UA_String expectedUris[1]; expectedUris[0] = UA_STRING("urn:open62541.test.server_register"); FindAndCheck(expectedUris, 1, NULL, NULL, "urn:open62541.test.server_register", NULL); }
END_TEST #endif // Test if discovery server lists himself as registered server, before any other registration. START_TEST(Client_find_discovery) { const UA_String expectedUris[] = {UA_STRING("urn:open62541.test.local_discovery_server")}; FindAndCheck(expectedUris, 1, NULL, NULL, NULL, NULL); }
} END_TEST START_TEST(GetMaximalConnectionConfigurationAndCompareValues){ UA_NetworkAddressUrlDataType networkAddressUrlData = {UA_STRING("127.0.0.1"), UA_STRING("opc.udp://224.0.0.22:4840/")}; UA_Variant address; UA_Variant_setScalar(&address, &networkAddressUrlData, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); UA_KeyValuePair connectionOptions[3]; connectionOptions[0].key = UA_QUALIFIEDNAME(0, "ttl"); UA_UInt32 ttl = 10; UA_Variant_setScalar(&connectionOptions[0].value, &ttl, &UA_TYPES[UA_TYPES_UINT32]); connectionOptions[1].key = UA_QUALIFIEDNAME(0, "loopback"); UA_Boolean loopback = UA_FALSE; UA_Variant_setScalar(&connectionOptions[1].value, &loopback, &UA_TYPES[UA_TYPES_UINT32]); connectionOptions[2].key = UA_QUALIFIEDNAME(0, "reuse"); UA_Boolean reuse = UA_TRUE; UA_Variant_setScalar(&connectionOptions[2].value, &reuse, &UA_TYPES[UA_TYPES_UINT32]); UA_PubSubConnectionConfig connectionConf; memset(&connectionConf, 0, sizeof(UA_PubSubConnectionConfig)); connectionConf.name = UA_STRING("UADP Connection"); connectionConf.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); connectionConf.enabled = true; connectionConf.publisherId.numeric = 223344; connectionConf.connectionPropertiesSize = 3; connectionConf.connectionProperties = connectionOptions; connectionConf.address = address; UA_NodeId connection; UA_StatusCode retVal = UA_Server_addPubSubConnection(server, &connectionConf, &connection); ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); UA_PubSubConnectionConfig connectionConfig; memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); retVal |= UA_Server_getPubSubConnectionConfig(server, connection, &connectionConfig); ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD); ck_assert(connectionConfig.connectionPropertiesSize == connectionConf.connectionPropertiesSize); ck_assert(UA_String_equal(&connectionConfig.name, &connectionConf.name) == UA_TRUE); ck_assert(UA_String_equal(&connectionConfig.transportProfileUri, &connectionConf.transportProfileUri) == UA_TRUE); UA_NetworkAddressUrlDataType networkAddressUrlDataCopy = *((UA_NetworkAddressUrlDataType *)connectionConfig.address.data); ck_assert(UA_NetworkAddressUrlDataType_calcSizeBinary(&networkAddressUrlDataCopy) == UA_NetworkAddressUrlDataType_calcSizeBinary(&networkAddressUrlData)); for(size_t i = 0; i < connectionConfig.connectionPropertiesSize; i++){ ck_assert(UA_String_equal(&connectionConfig.connectionProperties[i].key.name, &connectionConf.connectionProperties[i].key.name) == UA_TRUE); ck_assert(UA_Variant_calcSizeBinary(&connectionConfig.connectionProperties[i].value) == UA_Variant_calcSizeBinary(&connectionConf.connectionProperties[i].value)); } UA_PubSubConnectionConfig_deleteMembers(&connectionConfig); } END_TEST
static void setup(void) { server = UA_Server_new(); UA_ServerConfig *config = UA_Server_getConfig(server); UA_ServerConfig_setDefault(config); config->pubsubTransportLayers = (UA_PubSubTransportLayer *) UA_malloc(sizeof(UA_PubSubTransportLayer)); config->pubsubTransportLayers[0] = UA_PubSubTransportLayerUDPMP(); config->pubsubTransportLayersSize++; UA_Server_run_startup(server); UA_PubSubConnectionConfig connectionConfig; memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig)); connectionConfig.name = UA_STRING("UADP Connection"); UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL, UA_STRING("opc.udp://224.0.0.22:4840/")}; UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]); connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); UA_Server_addPubSubConnection(server, &connectionConfig, &connection1); }
int main(int argc, char **argv) { UA_String transportProfile = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"); UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL , UA_STRING("opc.udp://224.0.0.22:4840/")}; if (argc > 1) { if (strcmp(argv[1], "-h") == 0) { usage(argv[0]); return EXIT_SUCCESS; } else if (strncmp(argv[1], "opc.udp://", 10) == 0) { networkAddressUrl.url = UA_STRING(argv[1]); } else if (strncmp(argv[1], "opc.eth://", 10) == 0) { transportProfile = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"); if (argc < 3) { printf("Error: UADP/ETH needs an interface name\n"); return EXIT_FAILURE; } networkAddressUrl.networkInterface = UA_STRING(argv[2]); networkAddressUrl.url = UA_STRING(argv[1]); } else { printf("Error: unknown URI\n"); return EXIT_FAILURE; } } return run(&transportProfile, &networkAddressUrl); }
OV_DLLFNCEXPORT OV_RESULT opcuafb_NamespaceGetIndex_Execute_set( OV_INSTPTR_opcuafb_NamespaceGetIndex pinst, const OV_BOOL value ) { OV_INSTPTR_opcuafb_Connect pConnect = NULL; UA_String namespaceUri; UA_UInt16 NamespaceIndex = 0; UA_StatusCode result = UA_STATUSCODE_GOOD; 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; } //reuse memory for this temp string namespaceUri = UA_STRING(pinst->v_NamespaceUri); result = UA_Client_NamespaceGetIndex(pConnect->v_Client, &namespaceUri, &NamespaceIndex); if(result == UA_STATUSCODE_GOOD){ pinst->v_Error = FALSE; pinst->v_ErrorID = 0; pinst->v_Done = TRUE; pinst->v_NamespaceIndex = (OV_UINT)NamespaceIndex; }else{ pinst->v_Done = FALSE; pinst->v_Error = TRUE; pinst->v_ErrorID = 1; //todo } pinst->v_Execute = value; return OV_ERR_OK; }
static void addVariableFail(UA_Server *server) { /* Prepare the node attributes */ UA_VariableAttributes vAttr = UA_VariableAttributes_default; vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId; vAttr.valueRank = -1; /* a scalar. this is not allowed per the variable type */ vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable (fail)"); UA_String s = UA_STRING("2dpoint?"); UA_Variant_setScalar(&vAttr.value, &s, &UA_TYPES[UA_TYPES_STRING]); /* Add the node */ UA_Server_addVariableNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "2DPoint Type (fail)"), pointTypeId, vAttr, NULL, NULL); }
END_TEST START_TEST(Client_get_endpoints) { UA_String expectedEndpoints[1]; expectedEndpoints[0] = UA_STRING("opc.tcp://localhost:4840"); // general check if expected endpoints are returned GetEndpointsAndCheck("opc.tcp://localhost:4840", NULL,expectedEndpoints, 1); // check if filtering transport profile still returns the endpoint GetEndpointsAndCheck("opc.tcp://localhost:4840", "http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary", expectedEndpoints, 1); // filter transport profily by HTTPS, which should return no endpoint GetEndpointsAndCheck("opc.tcp://localhost:4840", "http://opcfoundation.org/UA-Profile/Transport/https-uabinary", NULL, 0); }
static void variables_basic(void) { /* Int32 */ UA_Int32 i = 5; UA_Int32 j; UA_Int32_copy(&i, &j); UA_Int32 *ip = UA_Int32_new(); UA_Int32_copy(&i, ip); UA_Int32_delete(ip); /* String */ UA_String s; UA_String_init(&s); /* _init zeroes out the entire memory of the datatype */ char *test = "test"; s.length = strlen(test); s.data = (UA_Byte*)test; UA_String s2; UA_String_copy(&s, &s2); UA_String_deleteMembers(&s2); /* Copying heap-allocated the dynamic content */ UA_String s3 = UA_STRING("test2"); UA_String s4 = UA_STRING_ALLOC("test2"); /* Copies the content to the heap */ UA_Boolean eq = UA_String_equal(&s3, &s4); UA_String_deleteMembers(&s4); if(!eq) return; /* Structured Type */ UA_ReadRequest rr; UA_init(&rr, &UA_TYPES[UA_TYPES_READREQUEST]); /* Generic method */ UA_ReadRequest_init(&rr); /* Shorthand for the previous line */ rr.requestHeader.timestamp = UA_DateTime_now(); /* Members of a structure */ rr.nodesToRead = (UA_ReadValueId *)UA_Array_new(5, &UA_TYPES[UA_TYPES_READVALUEID]); rr.nodesToReadSize = 5; /* Array size needs to be made known */ UA_ReadRequest *rr2 = UA_ReadRequest_new(); UA_copy(&rr, rr2, &UA_TYPES[UA_TYPES_READREQUEST]); UA_ReadRequest_deleteMembers(&rr); UA_ReadRequest_delete(rr2); }
static UA_StatusCode helloWorld(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output) { /* input is a scalar string (checked by the server) */ UA_String *name = (UA_String *)input[0].data; UA_String hello = UA_STRING("Hello "); UA_String greet; greet.length = hello.length + name->length; greet.data = (UA_Byte *)UA_malloc(greet.length); memcpy(greet.data, hello.data, hello.length); memcpy(greet.data + hello.length, name->data, name->length); UA_Variant_setScalarCopy(output, &greet, &UA_TYPES[UA_TYPES_STRING]); UA_String_deleteMembers(&greet); return UA_STATUSCODE_GOOD; }
END_TEST // Test if server filters locale START_TEST(Client_filter_locale) { UA_String expectedUris[2]; expectedUris[0] = UA_STRING("urn:open62541.test.local_discovery_server"), expectedUris[1] = UA_STRING("urn:open62541.test.server_register"); UA_String expectedNames[2]; expectedNames[0]= UA_STRING("LDS Server"); expectedNames[1]= UA_STRING("Anmeldungsserver"); UA_String expectedLocales[2]; expectedLocales[0] = UA_STRING("en"); expectedLocales[1] = UA_STRING("de"); // even if we request en-US, the server will return de-DE because it only has that name. FindAndCheck(expectedUris, 2, expectedLocales, expectedNames, NULL, "en"); }
int main(int argc, char **argv) { signal(SIGINT, stopHandler); /* catches ctrl-c */ signal(SIGTERM, stopHandler); #ifdef UA_ENABLE_ENCRYPTION if(argc < 3) { UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Missing arguments for encryption support. " "Arguments are <server-certificate.der> " "<private-key.der> [<trustlist1.crl>, ...]"); return 1; } /* Load certificate and private key */ UA_ByteString certificate = loadFile(argv[1]); UA_ByteString privateKey = loadFile(argv[2]); /* Load the trustlist */ size_t trustListSize = 0; if(argc > 3) trustListSize = (size_t)argc-3; UA_STACKARRAY(UA_ByteString, trustList, trustListSize); for(size_t i = 0; i < trustListSize; i++) trustList[i] = loadFile(argv[i+3]); /* Loading of a revocation list currently unsupported */ UA_ByteString *revocationList = NULL; size_t revocationListSize = 0; UA_ServerConfig *config = UA_ServerConfig_new_allSecurityPolicies(4840, &certificate, &privateKey, trustList, trustListSize, revocationList, revocationListSize); UA_ByteString_deleteMembers(&certificate); UA_ByteString_deleteMembers(&privateKey); for(size_t i = 0; i < trustListSize; i++) UA_ByteString_deleteMembers(&trustList[i]); if(!config) { UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Could not create the server config"); return 1; } #else if(argc < 2) { UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Missing argument for the server certificate"); return 1; } UA_ByteString certificate = loadFile(argv[1]); UA_ServerConfig *config = UA_ServerConfig_new_minimal(4840, &certificate); UA_ByteString_deleteMembers(&certificate); #endif /* uncomment next line to add a custom hostname */ // UA_ServerConfig_set_customHostname(config, UA_STRING("custom")); UA_Server *server = UA_Server_new(config); if(server == NULL) return 1; /* add a static variable node to the server */ UA_VariableAttributes myVar = UA_VariableAttributes_default; myVar.description = UA_LOCALIZEDTEXT("en-US", "the answer"); myVar.displayName = UA_LOCALIZEDTEXT("en-US", "the answer"); myVar.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; myVar.dataType = UA_TYPES[UA_TYPES_INT32].typeId; myVar.valueRank = -1; UA_Int32 myInteger = 42; UA_Variant_setScalarCopy(&myVar.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]); const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer"); const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId, myIntegerName, baseDataVariableType, myVar, NULL, NULL); UA_Variant_deleteMembers(&myVar.value); /* add a static variable that is readable but not writable*/ myVar = UA_VariableAttributes_default; myVar.description = UA_LOCALIZEDTEXT("en-US", "the answer - not readable"); myVar.displayName = UA_LOCALIZEDTEXT("en-US", "the answer - not readable"); myVar.accessLevel = UA_ACCESSLEVELMASK_WRITE; myVar.dataType = UA_TYPES[UA_TYPES_INT32].typeId; myVar.valueRank = -1; UA_Variant_setScalarCopy(&myVar.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]); const UA_QualifiedName myInteger2Name = UA_QUALIFIEDNAME(1, "the answer - not readable"); const UA_NodeId myInteger2NodeId = UA_NODEID_STRING(1, "the.answer.no.read"); UA_Server_addVariableNode(server, myInteger2NodeId, parentNodeId, parentReferenceNodeId, myInteger2Name, baseDataVariableType, myVar, NULL, NULL); UA_Variant_deleteMembers(&myVar.value); /* add a variable with the datetime data source */ UA_DataSource dateDataSource; dateDataSource.read = readTimeData; dateDataSource.write = NULL; UA_VariableAttributes v_attr = UA_VariableAttributes_default; v_attr.description = UA_LOCALIZEDTEXT("en-US", "current time"); v_attr.displayName = UA_LOCALIZEDTEXT("en-US", "current time"); v_attr.accessLevel = UA_ACCESSLEVELMASK_READ; v_attr.dataType = UA_TYPES[UA_TYPES_DATETIME].typeId; v_attr.valueRank = -1; const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time"); UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName, baseDataVariableType, v_attr, dateDataSource, NULL, NULL); /* Add HelloWorld method to the server */ #ifdef UA_ENABLE_METHODCALLS /* Method with IO Arguments */ UA_Argument inputArguments; UA_Argument_init(&inputArguments); inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId; inputArguments.description = UA_LOCALIZEDTEXT("en-US", "Say your name"); inputArguments.name = UA_STRING("Name"); inputArguments.valueRank = -1; /* scalar argument */ UA_Argument outputArguments; UA_Argument_init(&outputArguments); outputArguments.arrayDimensionsSize = 0; outputArguments.arrayDimensions = NULL; outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId; outputArguments.description = UA_LOCALIZEDTEXT("en-US", "Receive a greeting"); outputArguments.name = UA_STRING("greeting"); outputArguments.valueRank = -1; UA_MethodAttributes addmethodattributes = UA_MethodAttributes_default; addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "Hello World"); addmethodattributes.executable = true; addmethodattributes.userExecutable = true; UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, 62541), UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "hello_world"), addmethodattributes, &helloWorld, /* callback of the method node */ 1, &inputArguments, 1, &outputArguments, NULL, NULL); #endif /* Add folders for demo information model */ #define DEMOID 50000 #define SCALARID 50001 #define ARRAYID 50002 #define MATRIXID 50003 #define DEPTHID 50004 UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; object_attr.description = UA_LOCALIZEDTEXT("en-US", "Demo"); object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Demo"); UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL); object_attr.description = UA_LOCALIZEDTEXT("en-US", "Scalar"); object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Scalar"); UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Scalar"), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL); object_attr.description = UA_LOCALIZEDTEXT("en-US", "Array"); object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Array"); UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Array"), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL); object_attr.description = UA_LOCALIZEDTEXT("en-US", "Matrix"); object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Matrix"); UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL); /* Fill demo nodes for each type*/ UA_UInt32 id = 51000; // running id in namespace 0 for(UA_UInt32 type = 0; type < UA_TYPES_DIAGNOSTICINFO; type++) { if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO) continue; UA_VariableAttributes attr = UA_VariableAttributes_default; attr.valueRank = -2; attr.dataType = UA_TYPES[type].typeId; #ifndef UA_ENABLE_TYPENAMES char name[15]; #if defined(_WIN32) && !defined(__MINGW32__) sprintf_s(name, 15, "%02d", type); #else sprintf(name, "%02d", type); #endif attr.displayName = UA_LOCALIZEDTEXT("en-US", name); UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME(1, name); #else attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", UA_TYPES[type].typeName); UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME_ALLOC(1, UA_TYPES[type].typeName); #endif attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; attr.writeMask = UA_WRITEMASK_DISPLAYNAME | UA_WRITEMASK_DESCRIPTION; attr.userWriteMask = UA_WRITEMASK_DISPLAYNAME | UA_WRITEMASK_DESCRIPTION; /* add a scalar node for every built-in type */ void *value = UA_new(&UA_TYPES[type]); UA_Variant_setScalar(&attr.value, value, &UA_TYPES[type]); UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), qualifiedName, baseDataVariableType, attr, NULL, NULL); UA_Variant_deleteMembers(&attr.value); /* add an array node for every built-in type */ UA_Variant_setArray(&attr.value, UA_Array_new(10, &UA_TYPES[type]), 10, &UA_TYPES[type]); UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), qualifiedName, baseDataVariableType, attr, NULL, NULL); UA_Variant_deleteMembers(&attr.value); /* add an matrix node for every built-in type */ void *myMultiArray = UA_Array_new(9, &UA_TYPES[type]); attr.value.arrayDimensions = (UA_UInt32 *)UA_Array_new(2, &UA_TYPES[UA_TYPES_INT32]); attr.value.arrayDimensions[0] = 3; attr.value.arrayDimensions[1] = 3; attr.value.arrayDimensionsSize = 2; attr.value.arrayLength = 9; attr.value.data = myMultiArray; attr.value.type = &UA_TYPES[type]; UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), qualifiedName, baseDataVariableType, attr, NULL, NULL); UA_Variant_deleteMembers(&attr.value); #ifdef UA_ENABLE_TYPENAMES UA_LocalizedText_deleteMembers(&attr.displayName); UA_QualifiedName_deleteMembers(&qualifiedName); #endif } /* Hierarchy of depth 10 for CTT testing with forward and inverse references */ /* Enter node "depth 9" in CTT configuration - Project->Settings->Server Test->NodeIds->Paths->Starting Node 1 */ object_attr.description = UA_LOCALIZEDTEXT("en-US", "DepthDemo"); object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "DepthDemo"); UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEPTHID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "DepthDemo"), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL); id = DEPTHID; // running id in namespace 0 - Start with Matrix NODE for(UA_UInt32 i = 1; i <= 20; i++) { char name[15]; #if defined(_WIN32) && !defined(__MINGW32__) sprintf_s(name, 15, "depth%i", i); #else sprintf(name, "depth%i", i); #endif object_attr.description = UA_LOCALIZEDTEXT("en-US", name); object_attr.displayName = UA_LOCALIZEDTEXT("en-US", name); UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, id + i), UA_NODEID_NUMERIC(1, i == 1 ? DEPTHID : id + i - 1), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, name), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL); } /* Add the variable to some more places to get a node with three inverse references for the CTT */ UA_ExpandedNodeId answer_nodeid = UA_EXPANDEDNODEID_STRING(1, "the.answer"); UA_Server_addReference(server, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), answer_nodeid, true); UA_Server_addReference(server, UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), answer_nodeid, true); /* Example for manually setting an attribute within the server */ UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("en-US", "Objects"); UA_Server_writeDisplayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName); #define NOARGID 60000 #define INARGID 60001 #define OUTARGID 60002 #define INOUTARGID 60003 #ifdef UA_ENABLE_METHODCALLS /* adding some more method nodes to pass CTT */ /* Method without arguments */ addmethodattributes = UA_MethodAttributes_default; addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "noarg"); addmethodattributes.executable = true; addmethodattributes.userExecutable = true; UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, NOARGID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes, &noargMethod, /* callback of the method node */ 0, NULL, 0, NULL, NULL, NULL); /* Method with in arguments */ addmethodattributes = UA_MethodAttributes_default; addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "inarg"); addmethodattributes.executable = true; addmethodattributes.userExecutable = true; UA_Argument_init(&inputArguments); inputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId; inputArguments.description = UA_LOCALIZEDTEXT("en-US", "Input"); inputArguments.name = UA_STRING("Input"); inputArguments.valueRank = -1; //uaexpert will crash if set to 0 ;) UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, INARGID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes, &noargMethod, /* callback of the method node */ 1, &inputArguments, 0, NULL, NULL, NULL); /* Method with out arguments */ addmethodattributes = UA_MethodAttributes_default; addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "outarg"); addmethodattributes.executable = true; addmethodattributes.userExecutable = true; UA_Argument_init(&outputArguments); outputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId; outputArguments.description = UA_LOCALIZEDTEXT("en-US", "Output"); outputArguments.name = UA_STRING("Output"); outputArguments.valueRank = -1; UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, OUTARGID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "outarg"), addmethodattributes, &outargMethod, /* callback of the method node */ 0, NULL, 1, &outputArguments, NULL, NULL); /* Method with inout arguments */ addmethodattributes = UA_MethodAttributes_default; addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "inoutarg"); addmethodattributes.executable = true; addmethodattributes.userExecutable = true; UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, INOUTARGID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(1, "inoutarg"), addmethodattributes, &outargMethod, /* callback of the method node */ 1, &inputArguments, 1, &outputArguments, NULL, NULL); #endif /* run server */ UA_StatusCode retval = UA_Server_run(server, &running); UA_Server_delete(server); UA_ServerConfig_delete(config); return (int)retval; }
UA_StatusCode UA_Client_connect_async(UA_Client *client, const char *endpointUrl, UA_ClientAsyncServiceCallback callback, void *userdata) { UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Client internal async"); if(client->state >= UA_CLIENTSTATE_WAITING_FOR_ACK) return UA_STATUSCODE_GOOD; UA_ChannelSecurityToken_init(&client->channel.securityToken); client->channel.state = UA_SECURECHANNELSTATE_FRESH; client->endpointsHandshake = true; client->channel.sendSequenceNumber = 0; client->requestId = 0; UA_String_deleteMembers(&client->endpointUrl); client->endpointUrl = UA_STRING_ALLOC(endpointUrl); UA_StatusCode retval = UA_STATUSCODE_GOOD; client->connection = client->config.initConnectionFunc(client->config.localConnectionConfig, client->endpointUrl, client->config.timeout, &client->config.logger); if(client->connection.state != UA_CONNECTION_OPENING) { UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Could not init async connection"); retval = UA_STATUSCODE_BADCONNECTIONCLOSED; goto cleanup; } /* Set the channel SecurityMode if not done so far */ if(client->channel.securityMode == UA_MESSAGESECURITYMODE_INVALID) client->channel.securityMode = UA_MESSAGESECURITYMODE_NONE; /* Set the channel SecurityPolicy if not done so far */ if(!client->channel.securityPolicy) { UA_SecurityPolicy *sp = getSecurityPolicy(client, UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None")); if(!sp) { retval = UA_STATUSCODE_BADINTERNALERROR; goto cleanup; } UA_ByteString remoteCertificate = UA_BYTESTRING_NULL; retval = UA_SecureChannel_setSecurityPolicy(&client->channel, sp, &remoteCertificate); if(retval != UA_STATUSCODE_GOOD) goto cleanup; } client->asyncConnectCall.callback = callback; client->asyncConnectCall.userdata = userdata; if(!client->connection.connectCallbackID) { UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Adding async connection callback"); retval = UA_Client_addRepeatedCallback( client, client->config.pollConnectionFunc, &client->connection, 100.0, &client->connection.connectCallbackID); if(retval != UA_STATUSCODE_GOOD) goto cleanup; } retval = UA_SecureChannel_generateLocalNonce(&client->channel); if(retval != UA_STATUSCODE_GOOD) goto cleanup; /* Delete async service. TODO: Move this from connect to the disconnect/cleanup phase */ UA_Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSHUTDOWN); #ifdef UA_ENABLE_SUBSCRIPTIONS client->currentlyOutStandingPublishRequests = 0; #endif UA_NodeId_deleteMembers(&client->authenticationToken); /* Generate new local and remote key */ retval = UA_SecureChannel_generateNewKeys(&client->channel); if(retval != UA_STATUSCODE_GOOD) goto cleanup; return retval; cleanup: UA_LOG_TRACE(&client->config.logger, UA_LOGCATEGORY_CLIENT, "Failure during async connect"); UA_Client_disconnect(client); return retval; }
/* Combination of UA_Client_getEndpointsInternal and getEndpoints */ static void responseGetEndpoints(UA_Client *client, void *userdata, UA_UInt32 requestId, void *response) { UA_EndpointDescription* endpointArray = NULL; size_t endpointArraySize = 0; UA_GetEndpointsResponse* resp; resp = (UA_GetEndpointsResponse*)response; if (resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { client->connectStatus = resp->responseHeader.serviceResult; UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, "GetEndpointRequest failed with error code %s", UA_StatusCode_name (client->connectStatus)); UA_GetEndpointsResponse_deleteMembers(resp); return; } endpointArray = resp->endpoints; endpointArraySize = resp->endpointsSize; resp->endpoints = NULL; resp->endpointsSize = 0; UA_Boolean endpointFound = false; UA_Boolean tokenFound = false; UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); UA_String binaryTransport = UA_STRING("http://opcfoundation.org/UA-Profile/" "Transport/uatcp-uasc-uabinary"); // TODO: compare endpoint information with client->endpointUri for(size_t i = 0; i < endpointArraySize; ++i) { UA_EndpointDescription* endpoint = &endpointArray[i]; /* look out for binary transport endpoints */ /* Note: Siemens returns empty ProfileUrl, we will accept it as binary */ if(endpoint->transportProfileUri.length != 0 && !UA_String_equal (&endpoint->transportProfileUri, &binaryTransport)) continue; /* Look for an endpoint corresponding to the client security policy */ if(!UA_String_equal(&endpoint->securityPolicyUri, &client->channel.securityPolicy->policyUri)) continue; endpointFound = true; /* Look for a user token policy with an anonymous token */ for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) { UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j]; /* Usertokens also have a security policy... */ if(userToken->securityPolicyUri.length > 0 && !UA_String_equal(&userToken->securityPolicyUri, &securityNone)) continue; /* Does the token type match the client configuration? */ if((userToken->tokenType == UA_USERTOKENTYPE_ANONYMOUS && client->config.userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] && client->config.userIdentityToken.content.decoded.type != NULL) || (userToken->tokenType == UA_USERTOKENTYPE_USERNAME && client->config.userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) || (userToken->tokenType == UA_USERTOKENTYPE_CERTIFICATE && client->config.userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) || (userToken->tokenType == UA_USERTOKENTYPE_ISSUEDTOKEN && client->config.userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN])) continue; /* Endpoint with matching usertokenpolicy found */ tokenFound = true; UA_EndpointDescription_deleteMembers(&client->config.endpoint); UA_EndpointDescription_copy(endpoint, &client->config.endpoint); UA_UserTokenPolicy_deleteMembers(&client->config.userTokenPolicy); UA_UserTokenPolicy_copy(userToken, &client->config.userTokenPolicy); break; } } UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); if(!endpointFound) { UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, "No suitable endpoint found"); client->connectStatus = UA_STATUSCODE_BADINTERNALERROR; } else if(!tokenFound) { UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, "No suitable UserTokenPolicy found for the possible endpoints"); client->connectStatus = UA_STATUSCODE_BADINTERNALERROR; } requestSession(client, &requestId); }
void Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodRequest *request, UA_CallMethodResult *result) { /* Verify method/object relations. Object must have a hasComponent reference to the method node. */ UA_Boolean found = false; UA_NodeId hasComponentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASCOMPONENT); result->statusCode = isNodeInTree(server->nodestore, &request->methodId, &request->objectId, &hasComponentNodeId, 1, 1, &found); if(!found) result->statusCode = UA_STATUSCODE_BADMETHODINVALID; if(result->statusCode != UA_STATUSCODE_GOOD) return; /* Get/verify the method node */ const UA_MethodNode *methodCalled = (const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId); if(!methodCalled) { result->statusCode = UA_STATUSCODE_BADMETHODINVALID; return; } if(methodCalled->nodeClass != UA_NODECLASS_METHOD) { result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID; return; } if(!methodCalled->executable || !methodCalled->userExecutable || !methodCalled->attachedMethod) { result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE? return; } /* Get/verify the object node */ const UA_ObjectNode *withObject = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, &request->objectId); if(!withObject) { result->statusCode = UA_STATUSCODE_BADNODEIDINVALID; return; } if(withObject->nodeClass != UA_NODECLASS_OBJECT && withObject->nodeClass != UA_NODECLASS_OBJECTTYPE) { result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID; return; } /* Verify Input Argument count, types and sizes */ const UA_VariableNode *inputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments")); if(!inputArguments) { result->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT; return; } result->statusCode = argConformsToDefinition(server, inputArguments, request->inputArgumentsSize, request->inputArguments); if(result->statusCode != UA_STATUSCODE_GOOD) return; /* Allocate the output arguments */ const UA_VariableNode *outputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments")); if(!outputArguments) { result->statusCode = UA_STATUSCODE_BADINTERNALERROR; return; } result->outputArguments = UA_Array_new(outputArguments->value.variant.value.arrayLength, &UA_TYPES[UA_TYPES_VARIANT]); if(!result->outputArguments) { result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY; return; } result->outputArgumentsSize = outputArguments->value.variant.value.arrayLength; /* Call the method */ result->statusCode = methodCalled->attachedMethod(methodCalled->methodHandle, withObject->nodeId, request->inputArgumentsSize, request->inputArguments, result->outputArgumentsSize, result->outputArguments); /* TODO: Verify Output Argument count, types and sizes */ }