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 UA_StatusCode helloWorldMethod(const UA_NodeId objectId, const UA_Variant *input, UA_Variant *output, void *handle) { UA_String *inputStr = (UA_String*)input->data; UA_String tmp = UA_STRING_ALLOC("Hello "); if(inputStr->length > 0) { tmp.data = realloc(tmp.data, tmp.length + inputStr->length); memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length); tmp.length += inputStr->length; } UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]); UA_String_deleteMembers(&tmp); UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "Hello World was called"); return UA_STATUSCODE_GOOD; }
/* Example 3 */ static UA_StatusCode fooBarMethod(void *handle, const UA_NodeId objectId, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output) { /* the same as helloWorld, but returns foobar */ UA_String *inputStr = (UA_String*)input->data; UA_String tmp = UA_STRING_ALLOC("FooBar! "); if(inputStr->length > 0) { tmp.data = realloc(tmp.data, tmp.length + inputStr->length); memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length); tmp.length += inputStr->length; } UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]); UA_String_deleteMembers(&tmp); UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "FooBar was called"); return UA_STATUSCODE_GOOD; }
UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connectFunc, char *endpointUrl) { if(client->state == UA_CLIENTSTATE_CONNECTED) return UA_STATUSCODE_GOOD; if(client->state == UA_CLIENTSTATE_ERRORED) { UA_Client_reset(client); } UA_StatusCode retval = UA_STATUSCODE_GOOD; client->connection = connectFunc(UA_ConnectionConfig_standard, endpointUrl, client->logger); if(client->connection.state != UA_CONNECTION_OPENING) { retval = UA_STATUSCODE_BADCONNECTIONCLOSED; goto cleanup; } client->endpointUrl = UA_STRING_ALLOC(endpointUrl); if(client->endpointUrl.length < 0) { retval = UA_STATUSCODE_BADOUTOFMEMORY; goto cleanup; } client->connection.localConf = client->config.localConnectionConfig; retval = HelAckHandshake(client); if(retval == UA_STATUSCODE_GOOD) retval = SecureChannelHandshake(client, UA_FALSE); if(retval == UA_STATUSCODE_GOOD) retval = EndpointsHandshake(client); if(retval == UA_STATUSCODE_GOOD) retval = SessionHandshake(client); if(retval == UA_STATUSCODE_GOOD) retval = ActivateSession(client); if(retval == UA_STATUSCODE_GOOD) { client->connection.state = UA_CONNECTION_ESTABLISHED; client->state = UA_CLIENTSTATE_CONNECTED; } else { goto cleanup; } return retval; cleanup: client->state = UA_CLIENTSTATE_ERRORED; UA_Client_reset(client); return retval; }
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 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; }
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; }
static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew) { /* Check if sc is still valid */ if(renew && client->scExpiresAt - UA_DateTime_now() > client->config.timeToRenewSecureChannel * 10000) return UA_STATUSCODE_GOOD; UA_SecureConversationMessageHeader messageHeader; messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF; messageHeader.secureChannelId = 0; UA_SequenceHeader seqHeader; seqHeader.sequenceNumber = ++client->channel.sequenceNumber; seqHeader.requestId = ++client->requestId; UA_AsymmetricAlgorithmSecurityHeader asymHeader; UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader); asymHeader.securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None"); /* id of opensecurechannelrequest */ UA_NodeId requestType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY); UA_OpenSecureChannelRequest opnSecRq; UA_OpenSecureChannelRequest_init(&opnSecRq); opnSecRq.requestHeader.timestamp = UA_DateTime_now(); opnSecRq.requestHeader.authenticationToken = client->authenticationToken; opnSecRq.requestedLifetime = client->config.secureChannelLifeTime; if(renew) { opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW; UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to renew the SecureChannel"); } else { opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE; UA_ByteString_init(&client->channel.clientNonce); UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce); opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE; UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to open a SecureChannel"); } UA_ByteString message; UA_Connection *c = &client->connection; UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message); if(retval != UA_STATUSCODE_GOOD) { UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq); return retval; } size_t offset = 12; retval = UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &message, &offset); retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset); retval |= UA_NodeId_encodeBinary(&requestType, &message, &offset); retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset); messageHeader.messageHeader.messageSize = offset; offset = 0; retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &message, &offset); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq); if(retval != UA_STATUSCODE_GOOD) { client->connection.releaseSendBuffer(&client->connection, &message); return retval; } message.length = messageHeader.messageHeader.messageSize; retval = client->connection.send(&client->connection, &message); if(retval != UA_STATUSCODE_GOOD) return retval; UA_ByteString reply; UA_ByteString_init(&reply); do { retval = client->connection.recv(&client->connection, &reply, client->config.timeout); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Receiving OpenSecureChannelResponse failed"); return retval; } } while(!reply.data); offset = 0; UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &messageHeader); UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &asymHeader); UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader); UA_NodeId_decodeBinary(&reply, &offset, &requestType); UA_NodeId expectedRequest = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE + UA_ENCODINGOFFSET_BINARY); if(!UA_NodeId_equal(&requestType, &expectedRequest)) { UA_ByteString_deleteMembers(&reply); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_NodeId_deleteMembers(&requestType); UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT, "Reply answers the wrong request. Expected OpenSecureChannelResponse."); return UA_STATUSCODE_BADINTERNALERROR; } UA_OpenSecureChannelResponse response; UA_OpenSecureChannelResponse_init(&response); retval = UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response); if(retval != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Decoding OpenSecureChannelResponse failed"); UA_ByteString_deleteMembers(&reply); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); UA_OpenSecureChannelResponse_init(&response); response.responseHeader.serviceResult = retval; return retval; } client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000; UA_ByteString_deleteMembers(&reply); retval = response.responseHeader.serviceResult; if(retval != UA_STATUSCODE_GOOD) UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel could not be opened / renewed"); else if(!renew) { UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel.securityToken); /* if the handshake is repeated, replace the old nonce */ UA_ByteString_deleteMembers(&client->channel.serverNonce); UA_ByteString_copy(&response.serverNonce, &client->channel.serverNonce); UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel opened"); } else UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel renewed"); UA_OpenSecureChannelResponse_deleteMembers(&response); UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader); return retval; }
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; }