High Performance OPC UA Server SDK  1.2.0.193
sampleclient.c
/*****************************************************************************
* *
* Copyright (c) 2006-2016 Unified Automation GmbH. All rights reserved. *
* *
* Software License Agreement ("SLA") Version 2.6 *
* *
* Unless explicitly acquired and licensed from Licensor under another *
* license, the contents of this file are subject to the Software License *
* Agreement ("SLA") Version 2.6, or subsequent versions as allowed by the *
* SLA, and You may not copy or use this file in either source code or *
* executable form, except in compliance with the terms and conditions of *
* the SLA. *
* *
* All software distributed under the SLA is provided strictly on an "AS *
* IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, *
* AND LICENSOR HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT *
* LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR *
* PURPOSE, QUIET ENJOYMENT, OR NON-INFRINGEMENT. See the SLA for specific *
* language governing rights and limitations under the SLA. *
* *
* The complete license agreement can be found here: *
* http://unifiedautomation.com/License/SLA/2.6/ *
* *
*****************************************************************************/
#include <uaclient/uaclient.h>
#include <uaclient/uaclient_services.h>
#include <uaclient/uaclient_simple_browse.h>
#include <uabase/nodeid.h>
#include <trace/trace.h>
#include <memory/memory.h>
#include <common/errors.h>
#include <uabase/identifiers.h>
#include <uabase/datavalue.h>
#include <uabase/variant.h>
#include <uabase/structure/browseresultmask.h>
#include <uabase/structure/nodeclass.h>
#include <uabase/attributeid.h>
#include "sampleclient.h"
static int sample_client_browse_cb(
struct ua_client *client,
int client_result,
ua_statuscode service_result,
struct ua_browseresponse *res,
struct ua_browserequest *req,
void *cb_data)
{
struct ua_string result_string;
struct sample_client *ctx = cb_data;
int32_t i,j;
int ret;
UA_UNUSED(client);
if (client_result != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: service failed with errorcode=%i\n", __func__, client_result);
ctx->result = client_result;
ctx->cur_state = SAMPLE_CLIENT_STATE_DISCONNECT;
return 0;
} else if (service_result != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: service failed with statuscode=0x%08X\n", __func__, service_result);
ctx->result = UA_EBADSERVICERESPONSE;
ctx->cur_state = SAMPLE_CLIENT_STATE_DISCONNECT;
return 0;
}
for (i = 0; i < res->num_results; i++) {
ret = ua_nodeid_to_string(&req->nodes[i].node_id, &result_string);
if (ret == 0) {
printf("Browse result [%i](Source nodeid: %s, num_references: %i):\n",
i,
ua_string_const_data(&result_string),
ua_string_clear(&result_string);
} else {
printf("Browse result [%i](Source nodeid: %s, num_references: %i):\n",
i,
"<convert failed>",
}
for (j = 0; j < res->results[i].num_references; j++) {
ref = &res->results[i].references[j];
printf(" Reference [%i]:\n", j);
printf(" Display name: %s\n", ua_string_const_data(&ref->display_name.text));
ret = ua_nodeid_to_string(&ref->node_id.id, &result_string);
if (ret == 0) {
printf(" Target nodeid: %s\n", ua_string_const_data(&result_string));
ua_string_clear(&result_string);
} else {
printf(" Target nodeid: <convert failed>\n");
}
printf(" Nodeclass: %s\n", ua_nodeclass_to_string(ref->node_class));
}
}
ctx->cur_state = SAMPLE_CLIENT_STATE_DISCONNECT;
return 0;
}
static void sample_client_browse(struct sample_client *ctx)
{
struct ua_browserequest req;
int ret;
IPC_CLEAR(&req);
if (ret != 0) goto error;
req.nodes[0].include_subtypes = true;
req.nodes[0].node_class_mask = UA_NODECLASS_UNSPECIFIED; /* all nodeclasses */
req.nodes[0].result_mask = UA_BROWSERESULTMASK_ISFORWARD
| UA_BROWSERESULTMASK_DISPLAYNAME
| UA_BROWSERESULTMASK_NODECLASS;
ua_nodeid_set_numeric(&req.nodes[0].reference_type_id, 0, UA_ID_HIERARCHICALREFERENCES);
ua_nodeid_set_numeric(&req.nodes[0].node_id, 0, UA_ID_OBJECTSFOLDER);
req.nodes[1].include_subtypes = true;
req.nodes[1].node_class_mask = UA_NODECLASS_UNSPECIFIED; /* all nodeclasses */
req.nodes[1].result_mask = UA_BROWSERESULTMASK_ISFORWARD
| UA_BROWSERESULTMASK_DISPLAYNAME
| UA_BROWSERESULTMASK_NODECLASS;
ua_nodeid_set_numeric(&req.nodes[1].reference_type_id, 0, UA_ID_HIERARCHICALREFERENCES);
ua_nodeid_set_numeric(&req.nodes[1].node_id, 0, UA_ID_SERVER);
ret = ua_client_begin_simple_browse(&ctx->client, /* client context */
NULL, /* simple browse settings, optional */
&req, /* browserequest */
sample_client_browse_cb, /* callback function */
ctx); /* callback data */
if (ret != 0) goto error;
IPC_CLEAR(&req);
ctx->cur_state = SAMPLE_CLIENT_STATE_BROWSING;
return;
error:
ctx->result = ret;
ctx->cur_state = SAMPLE_CLIENT_STATE_BROWSE_DONE;
return;
}
static int sample_client_read_cb(
struct ua_client *client,
int client_result,
struct ua_responseheader *rh,
struct ua_readresponse *res,
struct ua_readrequest *req,
void *cb_data)
{
struct sample_client *ctx = cb_data;
struct ua_string result_string;
struct ua_datavalue *result;
int ret;
int32_t i;
UA_UNUSED(client);
UA_UNUSED(req);
if (client_result != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: service failed with errorcode=%i\n", __func__, client_result);
ctx->result = client_result;
ctx->cur_state = SAMPLE_CLIENT_STATE_DISCONNECT;
return 0;
} else if (rh->service_result != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: service failed with statuscode=0x%08X\n", __func__, rh->service_result);
ctx->result = UA_EBADSERVICERESPONSE;
ctx->cur_state = SAMPLE_CLIENT_STATE_DISCONNECT;
return 0;
} else if (res->num_results != 2) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: expected 2 results, but received %u\n", __func__, res->num_results);
ctx->result = UA_EBADINTERNALERROR;
ctx->cur_state = SAMPLE_CLIENT_STATE_DISCONNECT;
return 0;
}
for (i = 0; i < res->num_results; i++) {
result = &res->results[i];
printf("Read result [%i]:\n", i);
if (ua_statuscode_is_bad(result->status)) {
printf(" Bad statuscode=0x%08X\n", result->status);
continue;
}
ret = ua_variant_to_string(&result->value, &result_string);
if (ret != 0) {
printf(" Could not be converted with 'ua_variant_to_string'\n");
continue;
}
printf(" Value=%s\n", ua_string_const_data(&result_string));
ua_string_clear(&result_string);
}
ctx->cur_state = SAMPLE_CLIENT_STATE_READ_DONE;
return 0;
}
static void sample_client_read(struct sample_client *ctx)
{
struct ua_readrequest req;
int ret;
IPC_CLEAR(&req);
if (ret != 0) goto error;
req.nodes[0].attribute_id = UA_ATTRIBUTEID_VALUE;
ua_nodeid_set_numeric(&req.nodes[0].node_id, 0, UA_ID_SERVER_SERVERSTATUS_STATE);
req.nodes[1].attribute_id = UA_ATTRIBUTEID_VALUE;
ua_nodeid_set_numeric(&req.nodes[1].node_id, 0, UA_ID_SERVER_SERVERSTATUS_CURRENTTIME);
req.max_age = 0.0;
ret = ua_client_begin_read(
&ctx->client, /* client context */
NULL, /* service settings, optional */
&req, /* request */
sample_client_read_cb, /* callback function */
ctx); /* callback data */
if (ret != 0) goto error;
IPC_CLEAR(&req); /* client SDK is now responsible for this memory */
ctx->cur_state = SAMPLE_CLIENT_STATE_READING;
return;
error:
ctx->result = ret;
ctx->cur_state = SAMPLE_CLIENT_STATE_DISCONNECT;
return;
}
static void sample_client_connection_status_changed_cb(struct ua_client *client, enum ua_client_connection_status status)
{
const char *status_str = ua_client_connection_status_to_string(status);
UA_UNUSED(client);
printf("Connection Status Changed: %s\n", status_str);
}
static bool sample_client_connection_error_cb(struct ua_client *client,
enum ua_client_state state,
int client_error,
ua_statuscode statuscode)
{
struct sample_client *ctx = ua_client_get_userdata(client);
UA_UNUSED(state);
if (client_error != 0) {
printf("\nClient error: %i\n", client_error);
ctx->cur_state = SAMPLE_CLIENT_STATE_FINISHED;
ctx->result = -1; /* report connect failure */
}
if (statuscode != 0) {
printf("\nServer error: 0x%08X\n", statuscode);
ctx->cur_state = SAMPLE_CLIENT_STATE_FINISHED;
ctx->result = -1; /* report connect failure */
}
return false; /* true ignores error */
}
static void sample_client_disconnect_cb(struct ua_client *client, void *cb_data, int result, ua_statuscode statuscode)
{
struct sample_client *ctx = cb_data;
UA_UNUSED(client);
if (result != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: failed with errorcode=%i\n", __func__, result);
ctx->result = result;
} else if (statuscode != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: failed with statuscode=0x%08X\n", __func__, statuscode);
ctx->result = UA_EBADSERVICERESPONSE;
}
ctx->cur_state = SAMPLE_CLIENT_STATE_FINISHED;
}
static void sample_client_disconnect(struct sample_client *ctx)
{
int ret;
ret = ua_client_begin_disconnect(&ctx->client, sample_client_disconnect_cb, ctx);
if (ret != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: ua_client_begin_disconnect failed with errorcode=%i\n", __func__, ret);
/* In case of a previous error the client might already have lost the connection
to the server. Then ua_client_begin_disconnect fails and the disconnect step
is skipped in the state machine. */
if (ctx->result != 0) ctx->result = ret;
ctx->cur_state = SAMPLE_CLIENT_STATE_FINISHED;
} else {
ctx->cur_state = SAMPLE_CLIENT_STATE_DISCONNECTING;
}
}
static void sample_client_connect_cb(struct ua_client *client, void *cb_data, int result, ua_statuscode statuscode)
{
struct sample_client *ctx = cb_data;
UA_UNUSED(client);
if (result != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: failed with errorcode=%i\n", __func__, result);
ctx->result = result;
ctx->cur_state = SAMPLE_CLIENT_STATE_FINISHED;
} else if (statuscode != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: failed with statuscode=0x%08X\n", __func__, statuscode);
ctx->result = UA_EBADSERVICERESPONSE;
ctx->cur_state = SAMPLE_CLIENT_STATE_FINISHED;
} else {
TRACE_INFO(TRACE_FAC_USERAPPLICATION, "%s: successfully connected\n", __func__);
ctx->cur_state = SAMPLE_CLIENT_STATE_CONNECTED;
}
}
static void sample_client_connect(struct sample_client *ctx)
{
int ret;
ret = ua_client_begin_connect(&ctx->client, ctx->url, sample_client_connect_cb, ctx);
if (ret != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: ua_client_begin_connect failed with errorcode=%i\n", __func__, ret);
ctx->result = ret;
ctx->cur_state = SAMPLE_CLIENT_STATE_FINISHED;
} else {
ctx->cur_state = SAMPLE_CLIENT_STATE_CONNECTING;
}
}
int sample_client_get_result(struct sample_client *ctx)
{
return ctx->result;
}
void sample_client_cleanup(struct sample_client *ctx)
{
ua_client_cleanup(&ctx->client);
}
int sample_client_init(struct sample_client *ctx, const char *url)
{
struct ua_client_callbacks callbacks;
int ret;
ret = ua_client_init(&ctx->client);
if (ret != 0) {
TRACE_ERROR(TRACE_FAC_USERAPPLICATION, "%s: ua_client_init failed with errorcode=%i\n", __func__, ret);
return ret;
}
IPC_CLEAR(&callbacks);
callbacks.status_changed_cb = sample_client_connection_status_changed_cb;
/* TODO: improve or remove this callback? */
callbacks.error_cb = sample_client_connection_error_cb;
ua_client_set_callbacks(&ctx->client, &callbacks);
ua_client_set_userdata(&ctx->client, ctx);
ctx->cur_state = SAMPLE_CLIENT_STATE_INITIAL;
ctx->url = url;
ctx->result = 0;
return 0;
}
bool sample_client_check_state(struct sample_client *ctx)
{
switch (ctx->cur_state) {
case SAMPLE_CLIENT_STATE_INITIAL:
sample_client_connect(ctx);
break;
case SAMPLE_CLIENT_STATE_CONNECTED:
sample_client_read(ctx);
break;
case SAMPLE_CLIENT_STATE_READ_DONE:
sample_client_browse(ctx);
break;
case SAMPLE_CLIENT_STATE_BROWSE_DONE:
ctx->cur_state = SAMPLE_CLIENT_STATE_DISCONNECT;
break;
case SAMPLE_CLIENT_STATE_DISCONNECT:
sample_client_disconnect(ctx);
break;
case SAMPLE_CLIENT_STATE_FINISHED:
return false;
default:
break;;
}
return true;
}