mirror of
https://github.com/open62541/open62541.git
synced 2025-06-03 04:00:21 +00:00
commit
be9fbf4f61
@ -165,6 +165,7 @@ option(UA_ENABLE_SUBSCRIPTIONS_EVENTS "Enable event monitoring" ON)
|
||||
option(UA_ENABLE_DA "Enable OPC UA DataAccess (Part 8) definitions" ON)
|
||||
option(UA_ENABLE_HISTORIZING "Enable basic support for historical access (client and server)" OFF)
|
||||
option(UA_ENABLE_DISCOVERY "Enable Discovery Service (LDS)" OFF)
|
||||
option(UA_ENABLE_JSON_ENCODING "Enable JSON encoding" OFF)
|
||||
|
||||
option(UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS "Enable the use of A&C. (EXPERIMENTAL)" OFF)
|
||||
mark_as_advanced(UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS)
|
||||
@ -422,9 +423,6 @@ if(UA_ENABLE_PUBSUB_BUFMALLOC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(UA_ENABLE_JSON_ENCODING "Enable Json encoding (EXPERIMENTAL)" OFF)
|
||||
mark_as_advanced(UA_ENABLE_JSON_ENCODING)
|
||||
|
||||
option(UA_ENABLE_PUBSUB_MQTT "Enable publish/subscribe with mqtt (experimental)" OFF)
|
||||
mark_as_advanced(UA_ENABLE_PUBSUB_MQTT)
|
||||
if(UA_ENABLE_PUBSUB_MQTT)
|
||||
|
95
deps/jsmn/jsmn.c
vendored
95
deps/jsmn/jsmn.c
vendored
@ -2,6 +2,14 @@
|
||||
|
||||
#define JSMN_STRICT
|
||||
|
||||
/* what is the next expected element? */
|
||||
enum JSMN_NEXT {
|
||||
JSMN_KEY = 0,
|
||||
JSMN_COLON,
|
||||
JSMN_VALUE,
|
||||
JSMN_COMMA
|
||||
};
|
||||
|
||||
/**
|
||||
* Allocates a fresh unused token from the token pull.
|
||||
*/
|
||||
@ -151,11 +159,12 @@ static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
||||
* Parse JSON string and fill tokens.
|
||||
*/
|
||||
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
||||
jsmntok_t *tokens, unsigned int num_tokens) {
|
||||
jsmntok_t *tokens, unsigned int num_tokens) {
|
||||
int r;
|
||||
int i;
|
||||
jsmntok_t *token;
|
||||
unsigned int count = parser->toknext;
|
||||
enum JSMN_NEXT next = JSMN_VALUE;
|
||||
|
||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
||||
char c;
|
||||
@ -168,6 +177,8 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
||||
if (tokens == NULL) {
|
||||
break;
|
||||
}
|
||||
if(next != JSMN_VALUE)
|
||||
return JSMN_ERROR_INVAL;
|
||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
||||
if (token == NULL)
|
||||
return JSMN_ERROR_NOMEM;
|
||||
@ -180,11 +191,19 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
||||
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||
token->start = (int)parser->pos;
|
||||
parser->toksuper = (int)parser->toknext - 1;
|
||||
if(c == '{')
|
||||
next = JSMN_KEY;
|
||||
else
|
||||
next = JSMN_VALUE;
|
||||
break;
|
||||
case '}': case ']':
|
||||
if (tokens == NULL)
|
||||
break;
|
||||
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
||||
if(type == JSMN_OBJECT && next != JSMN_KEY && next != JSMN_COMMA)
|
||||
return JSMN_ERROR_INVAL;
|
||||
else if (type == JSMN_ARRAY && next != JSMN_VALUE && next != JSMN_COMMA)
|
||||
return JSMN_ERROR_INVAL;
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
if (parser->toknext < 1) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
@ -194,8 +213,8 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
||||
if (token->start != -1 && token->end == -1) {
|
||||
if (token->type != type) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
token->end = parser->pos + 1;
|
||||
}
|
||||
token->end = (int)parser->pos + 1;
|
||||
parser->toksuper = token->parent;
|
||||
break;
|
||||
}
|
||||
@ -208,19 +227,21 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
||||
token = &tokens[token->parent];
|
||||
}
|
||||
#else
|
||||
/* Find the surrounding token and close it */
|
||||
for (i = (int)parser->toknext - 1; i >= 0; i--) {
|
||||
token = &tokens[i];
|
||||
if (token->start != -1 && token->end == -1) {
|
||||
if (token->type != type) {
|
||||
if (token->type != type)
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
parser->toksuper = -1;
|
||||
token->end = (int)parser->pos + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Error if unmatched closing bracket */
|
||||
if (i == -1) return JSMN_ERROR_INVAL;
|
||||
if (i == -1)
|
||||
return JSMN_ERROR_INVAL;
|
||||
/* Find the new super token (first not closed) */
|
||||
for (; i >= 0; i--) {
|
||||
token = &tokens[i];
|
||||
if (token->start != -1 && token->end == -1) {
|
||||
@ -229,59 +250,67 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
next = JSMN_COMMA;
|
||||
break;
|
||||
case '\"':
|
||||
if(next == JSMN_KEY) {
|
||||
next = JSMN_COLON;
|
||||
} else if(next == JSMN_VALUE) {
|
||||
next = JSMN_COMMA;
|
||||
if (parser->toksuper != -1 && tokens != NULL)
|
||||
tokens[parser->toksuper].size++;
|
||||
} else {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
|
||||
if (r < 0) return r;
|
||||
count++;
|
||||
if (parser->toksuper != -1 && tokens != NULL)
|
||||
tokens[parser->toksuper].size++;
|
||||
break;
|
||||
case '\t' : case '\r' : case '\n' : case ' ':
|
||||
break;
|
||||
case ':':
|
||||
parser->toksuper = (int)parser->toknext - 1;
|
||||
if(next != JSMN_COLON) /* Must expect a colon */
|
||||
return JSMN_ERROR_INVAL;
|
||||
/* The current toksuper must be an object */
|
||||
if(parser->toknext == 0 ||
|
||||
tokens[parser->toksuper].type != JSMN_OBJECT)
|
||||
return JSMN_ERROR_INVAL;
|
||||
/* Previous token must be a string */
|
||||
if(tokens[parser->toknext - 1].type != JSMN_STRING)
|
||||
return JSMN_ERROR_INVAL;
|
||||
next = JSMN_VALUE;
|
||||
break;
|
||||
case ',':
|
||||
if (tokens != NULL && parser->toksuper != -1 &&
|
||||
tokens[parser->toksuper].type != JSMN_ARRAY &&
|
||||
tokens[parser->toksuper].type != JSMN_OBJECT) {
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
parser->toksuper = tokens[parser->toksuper].parent;
|
||||
#else
|
||||
for (i = (int)parser->toknext - 1; i >= 0; i--) {
|
||||
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
|
||||
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
||||
parser->toksuper = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(next != JSMN_COMMA) /* Must expect a comma */
|
||||
return JSMN_ERROR_INVAL;
|
||||
if(parser->toksuper == -1)
|
||||
return JSMN_ERROR_INVAL;
|
||||
if(tokens &&
|
||||
tokens[parser->toksuper].type != JSMN_ARRAY &&
|
||||
tokens[parser->toksuper].type != JSMN_OBJECT)
|
||||
return JSMN_ERROR_INVAL;
|
||||
if(tokens && tokens[parser->toksuper].type == JSMN_OBJECT)
|
||||
next = JSMN_KEY;
|
||||
else
|
||||
next = JSMN_VALUE;
|
||||
break;
|
||||
#ifdef JSMN_STRICT
|
||||
/* In strict mode primitives are: numbers and booleans */
|
||||
case '-': case '0': case '1' : case '2': case '3' : case '4':
|
||||
case '5': case '6': case '7' : case '8': case '9':
|
||||
case 't': case 'f': case 'n' :
|
||||
/* And they must not be keys of the object */
|
||||
if (tokens != NULL && parser->toksuper != -1) {
|
||||
jsmntok_t *t = &tokens[parser->toksuper];
|
||||
if (t->type == JSMN_OBJECT ||
|
||||
(t->type == JSMN_STRING && t->size != 0)) {
|
||||
return JSMN_ERROR_INVAL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* In non-strict mode every unquoted value is a primitive */
|
||||
default:
|
||||
#endif
|
||||
if(next != JSMN_VALUE)
|
||||
return JSMN_ERROR_INVAL;
|
||||
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
|
||||
if (r < 0) return r;
|
||||
count++;
|
||||
if (parser->toksuper != -1 && tokens != NULL)
|
||||
tokens[parser->toksuper].size++;
|
||||
next = JSMN_COMMA;
|
||||
break;
|
||||
|
||||
#ifdef JSMN_STRICT
|
||||
|
@ -2,12 +2,7 @@
|
||||
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
|
||||
|
||||
/**
|
||||
*
|
||||
* Attention! WIP: The event-filter mechanism is currently "Work in progress" and will be completed
|
||||
* soon. Some of the below defined filters are currently not working and will be completed
|
||||
* in on of the next event-filter-batches.
|
||||
*
|
||||
* When using events, the client is mostly only interested in a small selection of events.
|
||||
* When using events, the client is most often only interested in a small selection of events.
|
||||
* To avoid unnecessary event transmission, the client can configure filters. These filters
|
||||
* are part of the event-subscription configuration.
|
||||
*
|
||||
@ -28,8 +23,7 @@
|
||||
#define USE_FILTER_OR_TYPEOF
|
||||
|
||||
static UA_Boolean running = true;
|
||||
const size_t nSelectClauses = 2;
|
||||
const size_t nWhereClauses = 1;
|
||||
#define SELECT_CLAUSE_FIELD_COUNT 3
|
||||
|
||||
/**
|
||||
* Setting up SelectClauses
|
||||
@ -40,37 +34,30 @@ const size_t nWhereClauses = 1;
|
||||
* In this Example we are selecting two SimpleAttributeOperands to be returned, one as a Message and one as Severity.
|
||||
*/
|
||||
static UA_SimpleAttributeOperand *
|
||||
setupSelectClauses(void) {
|
||||
setupSelectClauses(size_t selectedFieldsSize, UA_QualifiedName *qName) {
|
||||
UA_SimpleAttributeOperand *selectClauses = (UA_SimpleAttributeOperand*)
|
||||
UA_Array_new(nSelectClauses, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
|
||||
UA_Array_new(selectedFieldsSize, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
|
||||
if(!selectClauses)
|
||||
return NULL;
|
||||
for(size_t i =0; i<nSelectClauses; ++i) {
|
||||
for(size_t i =0; i<selectedFieldsSize; ++i) {
|
||||
UA_SimpleAttributeOperand_init(&selectClauses[i]);
|
||||
}
|
||||
//configure Message field
|
||||
selectClauses[0].typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
|
||||
selectClauses[0].browsePathSize = 1;
|
||||
selectClauses[0].browsePath = (UA_QualifiedName*)
|
||||
UA_Array_new(selectClauses[0].browsePathSize, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
|
||||
if(!selectClauses[0].browsePath) {
|
||||
UA_SimpleAttributeOperand_delete(selectClauses);
|
||||
return NULL;
|
||||
}
|
||||
selectClauses[0].attributeId = UA_ATTRIBUTEID_VALUE;
|
||||
selectClauses[0].browsePath[0] = UA_QUALIFIEDNAME_ALLOC(0, "Message");
|
||||
//configure Severity field
|
||||
selectClauses[1].typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
|
||||
selectClauses[1].browsePathSize = 1;
|
||||
selectClauses[1].browsePath = (UA_QualifiedName*)
|
||||
UA_Array_new(selectClauses[1].browsePathSize, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
|
||||
if(!selectClauses[1].browsePath) {
|
||||
UA_SimpleAttributeOperand_delete(selectClauses);
|
||||
return NULL;
|
||||
}
|
||||
selectClauses[1].attributeId = UA_ATTRIBUTEID_VALUE;
|
||||
selectClauses[1].browsePath[0] = UA_QUALIFIEDNAME_ALLOC(0, "Severity");
|
||||
|
||||
for (size_t i = 0; i < selectedFieldsSize; ++i) {
|
||||
selectClauses[i].typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
|
||||
selectClauses[i].browsePathSize = 1;
|
||||
selectClauses[i].browsePath = (UA_QualifiedName*)
|
||||
UA_Array_new(selectClauses[i].browsePathSize, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
|
||||
if(!selectClauses[i].browsePath) {
|
||||
UA_SimpleAttributeOperand_delete(selectClauses);
|
||||
return NULL;
|
||||
}
|
||||
selectClauses[i].attributeId = UA_ATTRIBUTEID_VALUE;
|
||||
char fieldName[64];
|
||||
memcpy(fieldName, qName[i].name.data, qName[i].name.length);
|
||||
fieldName[qName[i].name.length] = '\0';
|
||||
selectClauses[i].browsePath[0] = UA_QUALIFIEDNAME_ALLOC(0, fieldName);
|
||||
}
|
||||
return selectClauses;
|
||||
}
|
||||
|
||||
@ -123,15 +110,22 @@ setupOfTypeFilter(UA_ContentFilterElement *element, UA_UInt16 nsIndex, UA_UInt32
|
||||
}
|
||||
|
||||
static void
|
||||
setupLiteralOperand(UA_ContentFilterElement *element, size_t count, UA_Variant *literals){
|
||||
for(size_t i = 0; i < count; ++i) {
|
||||
element->filterOperands[i].content.decoded.type = &UA_TYPES[UA_TYPES_LITERALOPERAND];
|
||||
element->filterOperands[i].encoding = UA_EXTENSIONOBJECT_DECODED;
|
||||
UA_LiteralOperand *literalOperand = UA_LiteralOperand_new();
|
||||
UA_LiteralOperand_init(literalOperand);
|
||||
literalOperand->value = literals[i];
|
||||
element->filterOperands[i].content.decoded.data = literalOperand;
|
||||
}
|
||||
setupLiteralOperand(UA_ContentFilterElement *element, size_t operandIndex, UA_Variant literal){
|
||||
element->filterOperands[operandIndex].content.decoded.type = &UA_TYPES[UA_TYPES_LITERALOPERAND];
|
||||
element->filterOperands[operandIndex].encoding = UA_EXTENSIONOBJECT_DECODED;
|
||||
UA_LiteralOperand *literalOperand = UA_LiteralOperand_new();
|
||||
UA_LiteralOperand_init(literalOperand);
|
||||
literalOperand->value = literal;
|
||||
element->filterOperands[operandIndex].content.decoded.data = literalOperand;
|
||||
}
|
||||
|
||||
static void
|
||||
setupSimpleAttributeOperand(UA_ContentFilterElement *element, size_t operandIndex, UA_SimpleAttributeOperand attributeOperand){
|
||||
element->filterOperands[operandIndex].content.decoded.type = &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND];
|
||||
element->filterOperands[operandIndex].encoding = UA_EXTENSIONOBJECT_DECODED;
|
||||
UA_SimpleAttributeOperand *simpleAttributeOperand = UA_SimpleAttributeOperand_new();
|
||||
*simpleAttributeOperand = attributeOperand;
|
||||
element->filterOperands[operandIndex].content.decoded.data = simpleAttributeOperand;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -152,6 +146,8 @@ setupLiteralOperand(UA_ContentFilterElement *element, size_t count, UA_Variant *
|
||||
* (EventTypeId == NodeID("CancelScanEvent") ||
|
||||
* (EventTypeId == NodeID("CancelScanFinishedEvent") ||
|
||||
* (EventTypeId == NodeID("ShutdownEvent"))
|
||||
* filterSelection 3:
|
||||
* ((OfType 5003 ) (and) ((Equal 99 == 99) (and) (Equal Event-Field "servity" > 99))
|
||||
*
|
||||
*/
|
||||
static UA_StatusCode
|
||||
@ -253,7 +249,7 @@ setupWhereClauses(UA_ContentFilter *contentFilter, UA_UInt16 whereClauseSize, UA
|
||||
contentFilter->elements[1].filterOperator = UA_FILTEROPERATOR_OFTYPE;
|
||||
contentFilter->elements[2].filterOperator = UA_FILTEROPERATOR_AND;
|
||||
contentFilter->elements[3].filterOperator = UA_FILTEROPERATOR_EQUALS;
|
||||
contentFilter->elements[4].filterOperator = UA_FILTEROPERATOR_EQUALS;
|
||||
contentFilter->elements[4].filterOperator = UA_FILTEROPERATOR_GREATERTHAN;
|
||||
|
||||
contentFilter->elements[0].filterOperandsSize = 2;
|
||||
contentFilter->elements[1].filterOperandsSize = 1;
|
||||
@ -273,13 +269,61 @@ setupWhereClauses(UA_ContentFilter *contentFilter, UA_UInt16 whereClauseSize, UA
|
||||
setupTwoOperandsFilter(&contentFilter->elements[2], 3, 4);
|
||||
setupOfTypeFilter(&contentFilter->elements[1], 1, 5000);
|
||||
|
||||
UA_UInt32 literal_value;
|
||||
UA_Variant literalContent[2];
|
||||
memset(literalContent, 0, sizeof(UA_Variant) * 2);
|
||||
UA_Variant_setScalar(&literalContent[0], &literal_value, &UA_TYPES[UA_TYPES_UINT32]);
|
||||
UA_Variant_setScalar(&literalContent[1], &literal_value, &UA_TYPES[UA_TYPES_UINT32]);
|
||||
setupLiteralOperand(&contentFilter->elements[3], 2, literalContent);
|
||||
setupLiteralOperand(&contentFilter->elements[4], 2, literalContent);
|
||||
UA_Variant literalContent;
|
||||
UA_Variant_init(&literalContent);
|
||||
UA_UInt32 literal_value = 99;
|
||||
UA_Variant_setScalarCopy(&literalContent, &literal_value, &UA_TYPES[UA_TYPES_UINT32]);
|
||||
|
||||
setupLiteralOperand(&contentFilter->elements[3], 0, literalContent);
|
||||
setupLiteralOperand(&contentFilter->elements[3], 1, literalContent);
|
||||
|
||||
UA_SimpleAttributeOperand sao;
|
||||
UA_SimpleAttributeOperand_init(&sao);
|
||||
sao.attributeId = UA_ATTRIBUTEID_VALUE;
|
||||
sao.typeDefinitionId = UA_NODEID_NUMERIC(0, 5000);
|
||||
sao.browsePathSize = 1;
|
||||
UA_QualifiedName *qn = UA_QualifiedName_new();
|
||||
*qn = UA_QUALIFIEDNAME_ALLOC(0, "Severity");
|
||||
sao.browsePath = qn;
|
||||
setupSimpleAttributeOperand(&contentFilter->elements[4], 0, sao);
|
||||
setupLiteralOperand(&contentFilter->elements[4], 1, literalContent);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
contentFilter->elements[0].filterOperator = UA_FILTEROPERATOR_AND;
|
||||
contentFilter->elements[1].filterOperator = UA_FILTEROPERATOR_OFTYPE;
|
||||
contentFilter->elements[2].filterOperator = UA_FILTEROPERATOR_GREATERTHAN;
|
||||
|
||||
contentFilter->elements[0].filterOperandsSize = 2;
|
||||
contentFilter->elements[1].filterOperandsSize = 1;
|
||||
contentFilter->elements[2].filterOperandsSize = 2;
|
||||
|
||||
/* Setup Operand Arrays */
|
||||
result = setupOperandArrays(contentFilter);
|
||||
if(result != UA_STATUSCODE_GOOD) {
|
||||
UA_ContentFilter_clear(contentFilter);
|
||||
return UA_STATUSCODE_BADCONFIGURATIONERROR;
|
||||
}
|
||||
|
||||
// init clauses
|
||||
setupTwoOperandsFilter(&contentFilter->elements[0], 1, 2);
|
||||
setupOfTypeFilter(&contentFilter->elements[1], 1, 5000);
|
||||
|
||||
UA_Variant literalContent;
|
||||
UA_Variant_init(&literalContent);
|
||||
UA_UInt32 literal_value = 99;
|
||||
UA_Variant_setScalarCopy(&literalContent, &literal_value, &UA_TYPES[UA_TYPES_UINT32]);
|
||||
|
||||
UA_SimpleAttributeOperand sao;
|
||||
UA_SimpleAttributeOperand_init(&sao);
|
||||
sao.attributeId = UA_ATTRIBUTEID_VALUE;
|
||||
sao.typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
|
||||
sao.browsePathSize = 1;
|
||||
UA_QualifiedName *qn = UA_QualifiedName_new();
|
||||
*qn = UA_QUALIFIEDNAME_ALLOC(0, "Severity");
|
||||
sao.browsePath = qn;
|
||||
setupSimpleAttributeOperand(&contentFilter->elements[2], 0, sao);
|
||||
setupLiteralOperand(&contentFilter->elements[2], 1, literalContent);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -302,6 +346,12 @@ handler_events_filter(UA_Client *client, UA_UInt32 subId, void *subContext,
|
||||
UA_LocalizedText *lt = (UA_LocalizedText *)eventFields[i].data;
|
||||
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
|
||||
"Message: '%.*s'", (int)lt->text.length, lt->text.data);
|
||||
} else if (UA_Variant_hasScalarType(&eventFields[i], &UA_TYPES[UA_TYPES_NODEID])) {
|
||||
UA_String nodeIdName = UA_STRING_ALLOC("");
|
||||
UA_NodeId_print((UA_NodeId *)eventFields[i].data, &nodeIdName);
|
||||
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
|
||||
"TypeNodeId: '%.*s'", (int)nodeIdName.length, nodeIdName.data);
|
||||
UA_String_clear(&nodeIdName);
|
||||
} else {
|
||||
#ifdef UA_ENABLE_TYPEDESCRIPTION
|
||||
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
|
||||
@ -325,7 +375,7 @@ int main(int argc, char *argv[]) {
|
||||
signal(SIGTERM, stopHandler);
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Usage: tutorial_client_events <opc.tcp://server-url>\n");
|
||||
printf("Usage: tutorial_client_event_filter <opc.tcp://server-url>\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@ -359,9 +409,16 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
UA_EventFilter filter;
|
||||
UA_EventFilter_init(&filter);
|
||||
filter.selectClauses = setupSelectClauses();
|
||||
filter.selectClausesSize = nSelectClauses;
|
||||
retval = setupWhereClauses(&filter.whereClause, 5, 3);
|
||||
UA_QualifiedName qm[SELECT_CLAUSE_FIELD_COUNT];
|
||||
qm[0].namespaceIndex = 0;
|
||||
qm[0].name = UA_STRING("Message");
|
||||
qm[1].namespaceIndex = 0;
|
||||
qm[1].name = UA_STRING("Severity");
|
||||
qm[2].namespaceIndex = 0;
|
||||
qm[2].name = UA_STRING("EventType");
|
||||
filter.selectClauses = setupSelectClauses(SELECT_CLAUSE_FIELD_COUNT, qm);
|
||||
filter.selectClausesSize = SELECT_CLAUSE_FIELD_COUNT;
|
||||
retval = setupWhereClauses(&filter.whereClause, 3, 4);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
UA_Client_delete(client);
|
||||
return EXIT_FAILURE;
|
||||
@ -395,7 +452,7 @@ int main(int argc, char *argv[]) {
|
||||
cleanup:
|
||||
UA_MonitoredItemCreateResult_clear(&result);
|
||||
UA_Client_Subscriptions_deleteSingle(client, response.subscriptionId);
|
||||
UA_Array_delete(filter.selectClauses, nSelectClauses, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
|
||||
UA_Array_delete(filter.selectClauses, SELECT_CLAUSE_FIELD_COUNT, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
|
||||
UA_Array_delete(filter.whereClause.elements, filter.whereClause.elementsSize, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT]);
|
||||
|
||||
UA_Client_disconnect(client);
|
||||
|
@ -198,7 +198,7 @@ generateRandomEventMethodCallback(UA_Server *server,
|
||||
UA_UInt32 random = (UA_UInt32) UA_UInt32_random() % SAMPLE_EVENT_TYPES_COUNT;
|
||||
/* set up event */
|
||||
UA_NodeId eventNodeId;
|
||||
UA_StatusCode retval = setUpEvent(server, &eventNodeId, eventTypes[random], true,random);
|
||||
UA_StatusCode retval = setUpEvent(server, &eventNodeId, eventTypes[random], true, random);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
|
||||
"Creating event failed. StatusCode %s", UA_StatusCode_name(retval));
|
||||
@ -213,6 +213,37 @@ generateRandomEventMethodCallback(UA_Server *server,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
generateCustomizedEventMethodCallback(UA_Server *server,
|
||||
const UA_NodeId *sessionId, void *sessionHandle,
|
||||
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) {
|
||||
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Creating customized event");
|
||||
UA_UInt16 *severity = (UA_UInt16*)input->data;
|
||||
UA_UInt32 random = (UA_UInt32) UA_UInt32_random() % SAMPLE_EVENT_TYPES_COUNT;
|
||||
UA_NodeId eventNodeId;
|
||||
UA_StatusCode retval = setUpEvent(server, &eventNodeId, eventTypes[random], true, random);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
|
||||
"Creating event failed. StatusCode %s", UA_StatusCode_name(retval));
|
||||
return retval;
|
||||
}
|
||||
//Overwrite severity
|
||||
UA_Server_writeObjectProperty_scalar(server, eventNodeId,
|
||||
UA_QUALIFIEDNAME(0, "Severity"),
|
||||
severity, &UA_TYPES[UA_TYPES_UINT16]);
|
||||
retval = UA_Server_triggerEvent(server, eventNodeId,
|
||||
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
|
||||
NULL, UA_TRUE);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
|
||||
"Triggering event failed. StatusCode %s", UA_StatusCode_name(retval));
|
||||
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
static void
|
||||
addGenerateSampleEventsMethod(UA_Server *server) {
|
||||
UA_MethodAttributes generateAttr = UA_MethodAttributes_default;
|
||||
@ -243,6 +274,28 @@ addGenerateSingleRandomEventMethod(UA_Server *server) {
|
||||
0, NULL, 0, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
addGenerateSingleCustomizedEventMethod(UA_Server *server) {
|
||||
UA_Argument inputArgument;
|
||||
UA_Argument_init(&inputArgument);
|
||||
inputArgument.description = UA_LOCALIZEDTEXT("en-US", "Severity");
|
||||
inputArgument.name = UA_STRING("Severity");
|
||||
inputArgument.dataType = UA_TYPES[UA_TYPES_UINT16].typeId;
|
||||
inputArgument.valueRank = UA_VALUERANK_SCALAR;
|
||||
|
||||
UA_MethodAttributes generateAttr = UA_MethodAttributes_default;
|
||||
generateAttr.description = UA_LOCALIZEDTEXT("en-US","Generate a customized event.");
|
||||
generateAttr.displayName = UA_LOCALIZEDTEXT("en-US","Generate customized event");
|
||||
generateAttr.executable = true;
|
||||
generateAttr.userExecutable = true;
|
||||
UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, 65002),
|
||||
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
||||
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
|
||||
UA_QUALIFIEDNAME(1, "Generate customized Event"),
|
||||
generateAttr, &generateCustomizedEventMethodCallback,
|
||||
1, &inputArgument, 0, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void stopHandler(int sig) {
|
||||
running = false;
|
||||
}
|
||||
@ -259,6 +312,7 @@ int main(int argc, char *argv[]) {
|
||||
addSampleEventTypes(server);
|
||||
addGenerateSampleEventsMethod(server);
|
||||
addGenerateSingleRandomEventMethod(server);
|
||||
addGenerateSingleCustomizedEventMethod(server);
|
||||
|
||||
UA_StatusCode retval = UA_Server_run(server, &running);
|
||||
|
||||
|
@ -33,6 +33,7 @@ int main(int argc, char **argv)
|
||||
|
||||
config->customDataTypes = &customTypesArray;
|
||||
|
||||
|
||||
UA_StatusCode retval;
|
||||
/* create nodes from nodeset */
|
||||
if(namespace_testnodeset_generated(server) != UA_STATUSCODE_GOOD) {
|
||||
|
@ -787,6 +787,10 @@ setInformationModel(UA_Server *server) {
|
||||
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
|
||||
/* Create the reusable event instance */
|
||||
UA_Server_createEvent(server, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE), &eventId);
|
||||
UA_UInt16 eventSeverity = 500;
|
||||
UA_Server_writeObjectProperty_scalar(server, eventId,
|
||||
UA_QUALIFIEDNAME(0, "Severity"),
|
||||
&eventSeverity, &UA_TYPES[UA_TYPES_UINT16]);
|
||||
|
||||
/* Trigger the event from two variables */
|
||||
UA_ValueCallback eventTriggerValueBackend;
|
||||
@ -1278,6 +1282,10 @@ int main(int argc, char **argv) {
|
||||
if(!enableAnon)
|
||||
disableAnonymous(&config);
|
||||
|
||||
/* Limit the number of SecureChannels and Sessions */
|
||||
config.maxSecureChannels = 10;
|
||||
config.maxSessions = 20;
|
||||
|
||||
/* Revolve the SecureChannel token every 300 seconds */
|
||||
config.maxSecurityTokenLifetime = 300000;
|
||||
|
||||
@ -1293,7 +1301,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
/* Set Subscription limits */
|
||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
||||
config.maxSubscriptions = 100;
|
||||
config.maxSubscriptions = 20;
|
||||
#endif
|
||||
|
||||
/* If RequestTimestamp is '0', log the warning and proceed */
|
||||
|
@ -1227,6 +1227,10 @@ UA_encodeJson(const void *src, const UA_DataType *type, UA_ByteString *outBuf,
|
||||
* Zero-out the entire structure initially to ensure code-compatibility when
|
||||
* more fields are added in a later release. */
|
||||
typedef struct {
|
||||
const UA_String *namespaces;
|
||||
size_t namespacesSize;
|
||||
const UA_String *serverUris;
|
||||
size_t serverUrisSize;
|
||||
const UA_DataTypeArray *customTypes; /* Begin of a linked list with custom
|
||||
* datatype definitions */
|
||||
} UA_DecodeJsonOptions;
|
||||
|
@ -12,23 +12,23 @@
|
||||
#include "ua_types_encoding_json.h"
|
||||
|
||||
/* Json keys for dsm */
|
||||
const char * UA_DECODEKEY_MESSAGES = ("Messages");
|
||||
const char * UA_DECODEKEY_MESSAGETYPE = ("MessageType");
|
||||
const char * UA_DECODEKEY_MESSAGEID = ("MessageId");
|
||||
const char * UA_DECODEKEY_PUBLISHERID = ("PublisherId");
|
||||
const char * UA_DECODEKEY_DATASETCLASSID = ("DataSetClassId");
|
||||
const char * UA_DECODEKEY_MESSAGES = "Messages";
|
||||
const char * UA_DECODEKEY_MESSAGETYPE = "MessageType";
|
||||
const char * UA_DECODEKEY_MESSAGEID = "MessageId";
|
||||
const char * UA_DECODEKEY_PUBLISHERID = "PublisherId";
|
||||
const char * UA_DECODEKEY_DATASETCLASSID = "DataSetClassId";
|
||||
|
||||
/* Json keys for dsm */
|
||||
const char * UA_DECODEKEY_DATASETWRITERID = ("DataSetWriterId");
|
||||
const char * UA_DECODEKEY_SEQUENCENUMBER = ("SequenceNumber");
|
||||
const char * UA_DECODEKEY_METADATAVERSION = ("MetaDataVersion");
|
||||
const char * UA_DECODEKEY_TIMESTAMP = ("Timestamp");
|
||||
const char * UA_DECODEKEY_DSM_STATUS = ("Status");
|
||||
const char * UA_DECODEKEY_PAYLOAD = ("Payload");
|
||||
const char * UA_DECODEKEY_DS_TYPE = ("Type");
|
||||
const char * UA_DECODEKEY_DATASETWRITERID = "DataSetWriterId";
|
||||
const char * UA_DECODEKEY_SEQUENCENUMBER = "SequenceNumber";
|
||||
const char * UA_DECODEKEY_METADATAVERSION = "MetaDataVersion";
|
||||
const char * UA_DECODEKEY_TIMESTAMP = "Timestamp";
|
||||
const char * UA_DECODEKEY_DSM_STATUS = "Status";
|
||||
const char * UA_DECODEKEY_PAYLOAD = "Payload";
|
||||
const char * UA_DECODEKEY_DS_TYPE = "Type";
|
||||
|
||||
/* -- json encoding/decoding -- */
|
||||
static UA_StatusCode writeJsonKey_UA_String(CtxJson *ctx, UA_String *in){
|
||||
static UA_StatusCode writeJsonKey_UA_String(CtxJson *ctx, UA_String *in) {
|
||||
UA_STACKARRAY(char, out, in->length + 1);
|
||||
memcpy(out, in->data, in->length);
|
||||
out[in->length] = 0;
|
||||
@ -36,8 +36,9 @@ static UA_StatusCode writeJsonKey_UA_String(CtxJson *ctx, UA_String *in){
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
UA_DataSetMessage_encodeJson_internal(const UA_DataSetMessage* src, UA_UInt16 dataSetWriterId,
|
||||
CtxJson *ctx){
|
||||
UA_DataSetMessage_encodeJson_internal(const UA_DataSetMessage* src,
|
||||
UA_UInt16 dataSetWriterId,
|
||||
CtxJson *ctx) {
|
||||
status rv = writeJsonObjStart(ctx);
|
||||
|
||||
/* DataSetWriterId */
|
||||
@ -56,7 +57,8 @@ UA_DataSetMessage_encodeJson_internal(const UA_DataSetMessage* src, UA_UInt16 da
|
||||
}
|
||||
|
||||
/* MetaDataVersion */
|
||||
if(src->header.configVersionMajorVersionEnabled || src->header.configVersionMinorVersionEnabled) {
|
||||
if(src->header.configVersionMajorVersionEnabled ||
|
||||
src->header.configVersionMinorVersionEnabled) {
|
||||
UA_ConfigurationVersionDataType cvd;
|
||||
cvd.majorVersion = src->header.configVersionMajorVersion;
|
||||
cvd.minorVersion = src->header.configVersionMinorVersion;
|
||||
@ -77,7 +79,7 @@ UA_DataSetMessage_encodeJson_internal(const UA_DataSetMessage* src, UA_UInt16 da
|
||||
/* Status */
|
||||
if(src->header.statusEnabled) {
|
||||
rv |= writeJsonObjElm(ctx, UA_DECODEKEY_DSM_STATUS,
|
||||
&src->header.status, &UA_TYPES[UA_TYPES_STATUSCODE]);
|
||||
&src->header.status, &UA_TYPES[UA_TYPES_UINT16]);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
@ -88,39 +90,36 @@ UA_DataSetMessage_encodeJson_internal(const UA_DataSetMessage* src, UA_UInt16 da
|
||||
/* TODO: currently no difference between delta and key frames. Own
|
||||
* dataSetMessageType for json?. If the field names are not defined, write
|
||||
* out empty field names. */
|
||||
if(src->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
|
||||
if(src->header.dataSetMessageType != UA_DATASETMESSAGE_DATAKEYFRAME)
|
||||
return UA_STATUSCODE_BADNOTSUPPORTED; /* Delta frames not supported */
|
||||
|
||||
if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
|
||||
/* KEYFRAME VARIANT */
|
||||
for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
|
||||
if(src->data.keyFrameData.fieldNames)
|
||||
rv |= writeJsonKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i]);
|
||||
else
|
||||
rv |= writeJsonKey(ctx, "");
|
||||
rv |= encodeJsonInternal(&(src->data.keyFrameData.dataSetFields[i].value),
|
||||
&UA_TYPES[UA_TYPES_VARIANT], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
|
||||
/* KEYFRAME DATAVALUE */
|
||||
for (UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
|
||||
if(src->data.keyFrameData.fieldNames)
|
||||
rv |= writeJsonKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i]);
|
||||
else
|
||||
rv |= writeJsonKey(ctx, "");
|
||||
rv |= encodeJsonInternal(&src->data.keyFrameData.dataSetFields[i],
|
||||
&UA_TYPES[UA_TYPES_DATAVALUE], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
/* RawData */
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
|
||||
/* KEYFRAME VARIANT */
|
||||
for(UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
|
||||
if(src->data.keyFrameData.fieldNames)
|
||||
rv |= writeJsonKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i]);
|
||||
else
|
||||
rv |= writeJsonKey(ctx, "");
|
||||
rv |= encodeJsonInternal(&(src->data.keyFrameData.dataSetFields[i].value),
|
||||
&UA_TYPES[UA_TYPES_VARIANT], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
} else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
|
||||
/* KEYFRAME DATAVALUE */
|
||||
for(UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
|
||||
if(src->data.keyFrameData.fieldNames)
|
||||
rv |= writeJsonKey_UA_String(ctx, &src->data.keyFrameData.fieldNames[i]);
|
||||
else
|
||||
rv |= writeJsonKey(ctx, "");
|
||||
rv |= encodeJsonInternal(&src->data.keyFrameData.dataSetFields[i],
|
||||
&UA_TYPES[UA_TYPES_DATAVALUE], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
/* DeltaFrame */
|
||||
return UA_STATUSCODE_BADNOTSUPPORTED;
|
||||
/* RawData */
|
||||
return UA_STATUSCODE_BADNOTIMPLEMENTED;
|
||||
}
|
||||
rv |= writeJsonObjEnd(ctx); /* Payload */
|
||||
rv |= writeJsonObjEnd(ctx); /* DataSetMessage */
|
||||
@ -191,18 +190,20 @@ UA_NetworkMessage_encodeJson_internal(const UA_NetworkMessage* src, CtxJson *ctx
|
||||
|
||||
/* Payload: DataSetMessages */
|
||||
UA_Byte count = src->payloadHeader.dataSetPayloadHeader.count;
|
||||
if(count > 0){
|
||||
UA_UInt16 *dataSetWriterIds = src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds;
|
||||
if(!dataSetWriterIds){
|
||||
if(count > 0) {
|
||||
UA_UInt16 *dataSetWriterIds =
|
||||
src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds;
|
||||
if(!dataSetWriterIds)
|
||||
return UA_STATUSCODE_BADENCODINGERROR;
|
||||
}
|
||||
|
||||
rv |= writeJsonKey(ctx, UA_DECODEKEY_MESSAGES);
|
||||
rv |= writeJsonArrStart(ctx); /* start array */
|
||||
|
||||
for (UA_UInt16 i = 0; i < count; i++) {
|
||||
const UA_DataSetMessage *dataSetMessages =
|
||||
src->payload.dataSetPayload.dataSetMessages;
|
||||
for(UA_UInt16 i = 0; i < count; i++) {
|
||||
writeJsonCommaIfNeeded(ctx);
|
||||
rv |= UA_DataSetMessage_encodeJson_internal(&src->payload.dataSetPayload.dataSetMessages[i],
|
||||
rv |= UA_DataSetMessage_encodeJson_internal(&dataSetMessages[i],
|
||||
dataSetWriterIds[i], ctx);
|
||||
if(rv != UA_STATUSCODE_GOOD)
|
||||
return rv;
|
||||
@ -218,9 +219,10 @@ UA_NetworkMessage_encodeJson_internal(const UA_NetworkMessage* src, CtxJson *ctx
|
||||
|
||||
UA_StatusCode
|
||||
UA_NetworkMessage_encodeJson(const UA_NetworkMessage *src,
|
||||
UA_Byte **bufPos, const UA_Byte **bufEnd, UA_String *namespaces,
|
||||
size_t namespaceSize, UA_String *serverUris,
|
||||
size_t serverUriSize, UA_Boolean useReversible) {
|
||||
UA_Byte **bufPos, const UA_Byte **bufEnd,
|
||||
UA_String *namespaces, size_t namespaceSize,
|
||||
UA_String *serverUris, size_t serverUriSize,
|
||||
UA_Boolean useReversible) {
|
||||
/* Set up the context */
|
||||
CtxJson ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
@ -246,7 +248,6 @@ UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage *src,
|
||||
UA_String *namespaces, size_t namespaceSize,
|
||||
UA_String *serverUris, size_t serverUriSize,
|
||||
UA_Boolean useReversible){
|
||||
|
||||
/* Set up the context */
|
||||
CtxJson ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
@ -266,19 +267,19 @@ UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage *src,
|
||||
return (size_t)ctx.pos;
|
||||
}
|
||||
|
||||
/* decode json */
|
||||
/* decode json */
|
||||
static status
|
||||
MetaDataVersion_decodeJsonInternal(void* cvd, const UA_DataType *type, CtxJson *ctx,
|
||||
ParseCtx *parseCtx, UA_Boolean moveToken){
|
||||
return decodeJsonInternal(cvd, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE],
|
||||
ctx, parseCtx, UA_TRUE);
|
||||
MetaDataVersion_decodeJsonInternal(void* cvd, const UA_DataType *type,
|
||||
CtxJson *ctx, ParseCtx *parseCtx) {
|
||||
return decodeJsonJumpTable[UA_DATATYPEKIND_STRUCTURE]
|
||||
(cvd, &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE], ctx, parseCtx);
|
||||
}
|
||||
|
||||
static status
|
||||
DataSetPayload_decodeJsonInternal(void* dsmP, const UA_DataType *type, CtxJson *ctx,
|
||||
ParseCtx *parseCtx, UA_Boolean moveToken) {
|
||||
DataSetPayload_decodeJsonInternal(void* dsmP, const UA_DataType *type,
|
||||
CtxJson *ctx, ParseCtx *parseCtx) {
|
||||
UA_DataSetMessage* dsm = (UA_DataSetMessage*)dsmP;
|
||||
dsm->header.dataSetMessageValid = UA_TRUE;
|
||||
dsm->header.dataSetMessageValid = true;
|
||||
if(isJsonNull(ctx, parseCtx)) {
|
||||
parseCtx->index++;
|
||||
return UA_STATUSCODE_GOOD;
|
||||
@ -297,7 +298,7 @@ DataSetPayload_decodeJsonInternal(void* dsmP, const UA_DataType *type, CtxJson *
|
||||
|
||||
/* iterate over the key/value pairs in the object. Keys are stored in fieldnames. */
|
||||
for(size_t i = 0; i < length; ++i) {
|
||||
ret = getDecodeSignature(UA_TYPES_STRING)(&fieldNames[i], type, ctx, parseCtx, UA_TRUE);
|
||||
ret = decodeJsonJumpTable[UA_DATATYPEKIND_STRING](&fieldNames[i], type, ctx, parseCtx);
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
return ret;
|
||||
|
||||
@ -307,19 +308,18 @@ DataSetPayload_decodeJsonInternal(void* dsmP, const UA_DataType *type, CtxJson *
|
||||
status foundBody = lookAheadForKey("Body", ctx, parseCtx, &searchResult);
|
||||
if(foundType == UA_STATUSCODE_GOOD && foundBody == UA_STATUSCODE_GOOD){
|
||||
dsm->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
|
||||
ret = getDecodeSignature(UA_TYPES_VARIANT)
|
||||
(&dsm->data.keyFrameData.dataSetFields[i].value, type, ctx, parseCtx, UA_TRUE);
|
||||
dsm->data.keyFrameData.dataSetFields[i].hasValue = UA_TRUE;
|
||||
ret = decodeJsonJumpTable[UA_DATATYPEKIND_VARIANT]
|
||||
(&dsm->data.keyFrameData.dataSetFields[i].value, type, ctx, parseCtx);
|
||||
dsm->data.keyFrameData.dataSetFields[i].hasValue = true;
|
||||
} else {
|
||||
dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
|
||||
ret = getDecodeSignature(UA_TYPES_DATAVALUE)
|
||||
(&dsm->data.keyFrameData.dataSetFields[i], type, ctx, parseCtx, UA_TRUE);
|
||||
dsm->data.keyFrameData.dataSetFields[i].hasValue = UA_TRUE;
|
||||
ret = decodeJsonJumpTable[UA_DATATYPEKIND_DATAVALUE]
|
||||
(&dsm->data.keyFrameData.dataSetFields[i], type, ctx, parseCtx);
|
||||
dsm->data.keyFrameData.dataSetFields[i].hasValue = true;
|
||||
}
|
||||
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -327,45 +327,35 @@ DataSetPayload_decodeJsonInternal(void* dsmP, const UA_DataType *type, CtxJson *
|
||||
|
||||
static status
|
||||
DatasetMessage_Payload_decodeJsonInternal(UA_DataSetMessage* dsm, const UA_DataType *type,
|
||||
CtxJson *ctx, ParseCtx *parseCtx, UA_Boolean moveToken) {
|
||||
CtxJson *ctx, ParseCtx *parseCtx) {
|
||||
UA_ConfigurationVersionDataType cvd;
|
||||
UA_UInt16 dataSetWriterId; /* the id is currently not processed */
|
||||
UA_UInt16 dataSetWriterId;
|
||||
|
||||
dsm->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
|
||||
|
||||
DecodeEntry entries[6] = {
|
||||
{UA_DECODEKEY_DATASETWRITERID, &dataSetWriterId,
|
||||
getDecodeSignature(UA_TYPES_UINT16), false, NULL},
|
||||
{UA_DECODEKEY_SEQUENCENUMBER, &dsm->header.dataSetMessageSequenceNr,
|
||||
getDecodeSignature(UA_TYPES_UINT16), false, NULL},
|
||||
{UA_DECODEKEY_METADATAVERSION, &cvd,
|
||||
&MetaDataVersion_decodeJsonInternal, false, NULL},
|
||||
{UA_DECODEKEY_TIMESTAMP, &dsm->header.timestamp,
|
||||
getDecodeSignature(UA_TYPES_DATETIME), false, NULL},
|
||||
{UA_DECODEKEY_DSM_STATUS, &dsm->header.status,
|
||||
getDecodeSignature(UA_TYPES_UINT16), false, NULL},
|
||||
{UA_DECODEKEY_PAYLOAD, dsm,
|
||||
&DataSetPayload_decodeJsonInternal, false, NULL}
|
||||
{UA_DECODEKEY_DATASETWRITERID, &dataSetWriterId, NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
|
||||
{UA_DECODEKEY_SEQUENCENUMBER, &dsm->header.dataSetMessageSequenceNr, NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
|
||||
{UA_DECODEKEY_METADATAVERSION, &cvd, &MetaDataVersion_decodeJsonInternal, false, NULL},
|
||||
{UA_DECODEKEY_TIMESTAMP, &dsm->header.timestamp, NULL, false, &UA_TYPES[UA_TYPES_DATETIME]},
|
||||
{UA_DECODEKEY_DSM_STATUS, &dsm->header.status, NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
|
||||
{UA_DECODEKEY_PAYLOAD, dsm, &DataSetPayload_decodeJsonInternal, false, NULL}
|
||||
};
|
||||
status ret = decodeFields(ctx, parseCtx, entries, 6);
|
||||
|
||||
status ret = decodeFields(ctx, parseCtx, entries, 6, NULL);
|
||||
if(ret != UA_STATUSCODE_GOOD || !entries[0].found){
|
||||
/* no dataSetwriterid. Is mandatory. Abort. */
|
||||
/* Error or no DatasetWriterId found or no payload found */
|
||||
if(ret != UA_STATUSCODE_GOOD || !entries[0].found || !entries[5].found)
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}else{
|
||||
if(parseCtx->custom != NULL){
|
||||
UA_UInt16* dataSetWriterIdsArray = (UA_UInt16*)parseCtx->custom;
|
||||
|
||||
if(parseCtx->currentCustomIndex < parseCtx->numCustom){
|
||||
dataSetWriterIdsArray[parseCtx->currentCustomIndex] = dataSetWriterId;
|
||||
parseCtx->currentCustomIndex++;
|
||||
}else{
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}
|
||||
}else{
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}
|
||||
}
|
||||
/* Set the DatasetWriterId in the context */
|
||||
if(!parseCtx->custom)
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
if(parseCtx->currentCustomIndex >= parseCtx->numCustom)
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
UA_UInt16* dataSetWriterIdsArray = (UA_UInt16*)parseCtx->custom;
|
||||
dataSetWriterIdsArray[parseCtx->currentCustomIndex] = dataSetWriterId;
|
||||
parseCtx->currentCustomIndex++;
|
||||
|
||||
dsm->header.dataSetMessageSequenceNrEnabled = entries[1].found;
|
||||
dsm->header.configVersionMajorVersion = cvd.majorVersion;
|
||||
dsm->header.configVersionMinorVersion = cvd.minorVersion;
|
||||
@ -373,21 +363,17 @@ DatasetMessage_Payload_decodeJsonInternal(UA_DataSetMessage* dsm, const UA_DataT
|
||||
dsm->header.configVersionMinorVersionEnabled = entries[2].found;
|
||||
dsm->header.timestampEnabled = entries[3].found;
|
||||
dsm->header.statusEnabled = entries[4].found;
|
||||
if(!entries[5].found){
|
||||
/* No payload found */
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}
|
||||
|
||||
dsm->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
|
||||
dsm->header.picoSecondsIncluded = UA_FALSE;
|
||||
dsm->header.dataSetMessageValid = UA_TRUE;
|
||||
dsm->header.picoSecondsIncluded = false;
|
||||
dsm->header.dataSetMessageValid = true;
|
||||
dsm->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
|
||||
return ret;
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
static status
|
||||
DatasetMessage_Array_decodeJsonInternal(void *UA_RESTRICT dst, const UA_DataType *type,
|
||||
CtxJson *ctx, ParseCtx *parseCtx, UA_Boolean moveToken) {
|
||||
CtxJson *ctx, ParseCtx *parseCtx) {
|
||||
/* Array! */
|
||||
if(getJsmnType(parseCtx) != JSMN_ARRAY)
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
@ -398,8 +384,9 @@ DatasetMessage_Array_decodeJsonInternal(void *UA_RESTRICT dst, const UA_DataType
|
||||
return UA_STATUSCODE_GOOD;
|
||||
|
||||
/* Allocate memory */
|
||||
UA_DataSetMessage *dsm = (UA_DataSetMessage*)UA_calloc(length, sizeof(UA_DataSetMessage));
|
||||
if(dsm == NULL)
|
||||
UA_DataSetMessage *dsm = (UA_DataSetMessage*)
|
||||
UA_calloc(length, sizeof(UA_DataSetMessage));
|
||||
if(!dsm)
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
|
||||
/* Copy new Pointer do dest */
|
||||
@ -411,7 +398,7 @@ DatasetMessage_Array_decodeJsonInternal(void *UA_RESTRICT dst, const UA_DataType
|
||||
status ret = UA_STATUSCODE_BADDECODINGERROR;
|
||||
/* Decode array members */
|
||||
for(size_t i = 0; i < length; ++i) {
|
||||
ret = DatasetMessage_Payload_decodeJsonInternal(&dsm[i], NULL, ctx, parseCtx, UA_TRUE);
|
||||
ret = DatasetMessage_Payload_decodeJsonInternal(&dsm[i], NULL, ctx, parseCtx);
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
return ret;
|
||||
}
|
||||
@ -419,27 +406,27 @@ DatasetMessage_Array_decodeJsonInternal(void *UA_RESTRICT dst, const UA_DataType
|
||||
return ret;
|
||||
}
|
||||
|
||||
static status NetworkMessage_decodeJsonInternal(UA_NetworkMessage *dst, CtxJson *ctx,
|
||||
ParseCtx *parseCtx) {
|
||||
static status
|
||||
NetworkMessage_decodeJsonInternal(UA_NetworkMessage *dst, CtxJson *ctx,
|
||||
ParseCtx *parseCtx) {
|
||||
memset(dst, 0, sizeof(UA_NetworkMessage));
|
||||
dst->chunkMessage = UA_FALSE;
|
||||
dst->groupHeaderEnabled = UA_FALSE;
|
||||
dst->payloadHeaderEnabled = UA_FALSE;
|
||||
dst->picosecondsEnabled = UA_FALSE;
|
||||
dst->promotedFieldsEnabled = UA_FALSE;
|
||||
dst->chunkMessage = false;
|
||||
dst->groupHeaderEnabled = false;
|
||||
dst->payloadHeaderEnabled = false;
|
||||
dst->picosecondsEnabled = false;
|
||||
dst->promotedFieldsEnabled = false;
|
||||
|
||||
/* Look forward for publisheId, if present check if type if primitve (Number) or String. */
|
||||
u8 publishIdTypeIndex = UA_TYPES_STRING;
|
||||
const UA_DataType *pubIdType = &UA_TYPES[UA_TYPES_STRING];
|
||||
size_t searchResultPublishIdType = 0;
|
||||
status found = lookAheadForKey(UA_DECODEKEY_PUBLISHERID, ctx,
|
||||
parseCtx, &searchResultPublishIdType);
|
||||
if(found == UA_STATUSCODE_GOOD) {
|
||||
jsmntok_t publishIdToken = parseCtx->tokenArray[searchResultPublishIdType];
|
||||
if(publishIdToken.type == JSMN_PRIMITIVE) {
|
||||
publishIdTypeIndex = UA_TYPES_UINT64;
|
||||
pubIdType = &UA_TYPES[UA_TYPES_UINT64];
|
||||
dst->publisherIdType = UA_PUBLISHERDATATYPE_UINT64; //store in biggest possible
|
||||
} else if(publishIdToken.type == JSMN_STRING) {
|
||||
publishIdTypeIndex = UA_TYPES_STRING;
|
||||
dst->publisherIdType = UA_PUBLISHERDATATYPE_STRING;
|
||||
} else {
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
@ -462,21 +449,22 @@ static status NetworkMessage_decodeJsonInternal(UA_NetworkMessage *dst, CtxJson
|
||||
parseCtx->numCustom = messageCount;
|
||||
|
||||
/* MessageType */
|
||||
UA_Boolean isUaData = UA_TRUE;
|
||||
UA_Boolean isUaData = true;
|
||||
size_t searchResultMessageType = 0;
|
||||
found = lookAheadForKey(UA_DECODEKEY_MESSAGETYPE, ctx, parseCtx, &searchResultMessageType);
|
||||
if(found != UA_STATUSCODE_GOOD)
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
size_t size = (size_t)(parseCtx->tokenArray[searchResultMessageType].end - parseCtx->tokenArray[searchResultMessageType].start);
|
||||
size_t size = (size_t)(parseCtx->tokenArray[searchResultMessageType].end -
|
||||
parseCtx->tokenArray[searchResultMessageType].start);
|
||||
char* msgType = (char*)(ctx->pos + parseCtx->tokenArray[searchResultMessageType].start);
|
||||
if(size == 7) { //ua-data
|
||||
if(strncmp(msgType, "ua-data", size) != 0)
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
isUaData = UA_TRUE;
|
||||
isUaData = true;
|
||||
} else if(size == 11) { //ua-metadata
|
||||
if(strncmp(msgType, "ua-metadata", size) != 0)
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
isUaData = UA_FALSE;
|
||||
isUaData = false;
|
||||
} else {
|
||||
return UA_STATUSCODE_BADDECODINGERROR;
|
||||
}
|
||||
@ -488,18 +476,18 @@ static status NetworkMessage_decodeJsonInternal(UA_NetworkMessage *dst, CtxJson
|
||||
/* Network Message */
|
||||
UA_String messageType;
|
||||
DecodeEntry entries[5] = {
|
||||
{UA_DECODEKEY_MESSAGEID, &dst->messageId, getDecodeSignature(UA_TYPES_STRING), false, NULL},
|
||||
{UA_DECODEKEY_MESSAGEID, &dst->messageId, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
|
||||
{UA_DECODEKEY_MESSAGETYPE, &messageType, NULL, false, NULL},
|
||||
{UA_DECODEKEY_PUBLISHERID, &dst->publisherId.publisherIdString, getDecodeSignature(publishIdTypeIndex), false, NULL},
|
||||
{UA_DECODEKEY_DATASETCLASSID, &dst->dataSetClassId, getDecodeSignature(UA_TYPES_GUID), false, NULL},
|
||||
{UA_DECODEKEY_PUBLISHERID, &dst->publisherId.publisherIdString, NULL, false, pubIdType},
|
||||
{UA_DECODEKEY_DATASETCLASSID, &dst->dataSetClassId, NULL, false, &UA_TYPES[UA_TYPES_GUID]},
|
||||
{UA_DECODEKEY_MESSAGES, &dst->payload.dataSetPayload.dataSetMessages, &DatasetMessage_Array_decodeJsonInternal, false, NULL}
|
||||
};
|
||||
|
||||
//Store publisherId in correct union
|
||||
if(publishIdTypeIndex == UA_TYPES_UINT64)
|
||||
if(pubIdType == &UA_TYPES[UA_TYPES_UINT64])
|
||||
entries[2].fieldPointer = &dst->publisherId.publisherIdUInt64;
|
||||
|
||||
status ret = decodeFields(ctx, parseCtx, entries, 5, NULL);
|
||||
status ret = decodeFields(ctx, parseCtx, entries, 5);
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
return ret;
|
||||
|
||||
@ -508,26 +496,29 @@ static status NetworkMessage_decodeJsonInternal(UA_NetworkMessage *dst, CtxJson
|
||||
if(dst->publisherIdEnabled)
|
||||
dst->publisherIdType = UA_PUBLISHERDATATYPE_STRING;
|
||||
dst->dataSetClassIdEnabled = entries[3].found;
|
||||
dst->payloadHeaderEnabled = UA_TRUE;
|
||||
dst->payloadHeaderEnabled = true;
|
||||
dst->payloadHeader.dataSetPayloadHeader.count = (UA_Byte)messageCount;
|
||||
|
||||
//Set the dataSetWriterIds. They are filled in the dataSet decoding.
|
||||
/* Set the dataSetWriterIds. They are filled in the dataSet decoding. */
|
||||
dst->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = (UA_UInt16*)parseCtx->custom;
|
||||
return ret;
|
||||
}
|
||||
|
||||
status UA_NetworkMessage_decodeJson(UA_NetworkMessage *dst, const UA_ByteString *src){
|
||||
status
|
||||
UA_NetworkMessage_decodeJson(UA_NetworkMessage *dst, const UA_ByteString *src) {
|
||||
/* Set up the context */
|
||||
CtxJson ctx;
|
||||
memset(&ctx, 0, sizeof(CtxJson));
|
||||
ParseCtx parseCtx;
|
||||
memset(&parseCtx, 0, sizeof(ParseCtx));
|
||||
parseCtx.tokenArray = (jsmntok_t*)UA_malloc(sizeof(jsmntok_t) * UA_JSON_MAXTOKENCOUNT);
|
||||
parseCtx.tokenArray = (jsmntok_t*)
|
||||
UA_malloc(sizeof(jsmntok_t) * UA_JSON_MAXTOKENCOUNT);
|
||||
if(!parseCtx.tokenArray)
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
memset(parseCtx.tokenArray, 0, sizeof(jsmntok_t) * UA_JSON_MAXTOKENCOUNT);
|
||||
status ret = tokenize(&parseCtx, &ctx, src);
|
||||
if(ret != UA_STATUSCODE_GOOD){
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
return ret;
|
||||
}
|
||||
ret = NetworkMessage_decodeJsonInternal(dst, &ctx, &parseCtx);
|
||||
UA_free(parseCtx.tokenArray);
|
||||
return ret;
|
||||
|
@ -16,6 +16,7 @@
|
||||
* Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang)
|
||||
* Copyright 2019 (c) Kalycito Infotech Private Limited
|
||||
* Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
|
||||
* Copyright 2022 (c) Fraunhofer IOSB (Author: Andreas Ebner)
|
||||
*/
|
||||
|
||||
#include "ua_server_internal.h"
|
||||
@ -534,8 +535,7 @@ UA_Server_getStatistics(UA_Server *server) {
|
||||
stat.ns = server->networkStatistics;
|
||||
stat.scs = server->secureChannelStatistics;
|
||||
|
||||
stat.ss.currentSessionCount =
|
||||
server->serverDiagnosticsSummary.currentSessionCount;
|
||||
stat.ss.currentSessionCount = server->activeSessionCount;
|
||||
stat.ss.cumulatedSessionCount =
|
||||
server->serverDiagnosticsSummary.cumulatedSessionCount;
|
||||
stat.ss.securityRejectedSessionCount =
|
||||
@ -679,6 +679,13 @@ UA_Server_run_startup(UA_Server *server) {
|
||||
startMulticastDiscoveryServer(server);
|
||||
#endif
|
||||
|
||||
/* Update Endpoint description */
|
||||
for(size_t i = 0; i < server->config.endpointsSize; ++i){
|
||||
UA_ApplicationDescription_clear(&server->config.endpoints[i].server);
|
||||
UA_ApplicationDescription_copy(&server->config.applicationDescription,
|
||||
&server->config.endpoints[i].server);
|
||||
}
|
||||
|
||||
server->state = UA_SERVERLIFECYCLE_FRESH;
|
||||
|
||||
return result;
|
||||
|
@ -40,10 +40,10 @@ void UA_debug_dumpCompleteChunk(UA_Server *const server, UA_Connection *const co
|
||||
/********************/
|
||||
|
||||
UA_StatusCode
|
||||
sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, UA_UInt32 requestHandle,
|
||||
const UA_DataType *responseType, UA_StatusCode statusCode) {
|
||||
UA_Response response;
|
||||
UA_init(&response, responseType);
|
||||
sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId,
|
||||
UA_UInt32 requestHandle, UA_StatusCode statusCode) {
|
||||
UA_ServiceFault response;
|
||||
UA_ServiceFault_init(&response);
|
||||
UA_ResponseHeader *responseHeader = &response.responseHeader;
|
||||
responseHeader->requestHandle = requestHandle;
|
||||
responseHeader->timestamp = UA_DateTime_now();
|
||||
@ -55,11 +55,12 @@ sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, UA_UInt32 reque
|
||||
|
||||
/* Send error message. Message type is MSG and not ERR, since we are on a
|
||||
* SecureChannel! */
|
||||
return UA_SecureChannel_sendSymmetricMessage(channel, requestId, UA_MESSAGETYPE_MSG,
|
||||
&response, responseType);
|
||||
return UA_SecureChannel_sendSymmetricMessage(channel, requestId,
|
||||
UA_MESSAGETYPE_MSG, &response,
|
||||
&UA_TYPES[UA_TYPES_SERVICEFAULT]);
|
||||
}
|
||||
|
||||
/* This is not an ERR message, the connection is not closed afterwards */
|
||||
/* This is not an ERR message, the connection is not closed afterwards */
|
||||
static UA_StatusCode
|
||||
decodeHeaderSendServiceFault(UA_SecureChannel *channel, const UA_ByteString *msg,
|
||||
size_t offset, const UA_DataType *responseType,
|
||||
@ -70,8 +71,7 @@ decodeHeaderSendServiceFault(UA_SecureChannel *channel, const UA_ByteString *msg
|
||||
&UA_TYPES[UA_TYPES_REQUESTHEADER], NULL);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
retval = sendServiceFault(channel, requestId, requestHeader.requestHandle,
|
||||
responseType, error);
|
||||
retval = sendServiceFault(channel, requestId, requestHeader.requestHandle, error);
|
||||
UA_RequestHeader_clear(&requestHeader);
|
||||
return retval;
|
||||
}
|
||||
@ -454,6 +454,11 @@ sendResponse(UA_Server *server, UA_Session *session, UA_SecureChannel *channel,
|
||||
if(!channel)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
/* If the overall service call failed, answer with a ServiceFault */
|
||||
if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
|
||||
return sendServiceFault(channel, requestId, response->responseHeader.requestHandle,
|
||||
response->responseHeader.serviceResult);
|
||||
|
||||
/* Prepare the ResponseHeader */
|
||||
response->responseHeader.timestamp = UA_DateTime_now();
|
||||
|
||||
@ -569,7 +574,7 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques
|
||||
) {
|
||||
serviceRes = UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
|
||||
channelRes = sendServiceFault(channel, requestId, requestHeader->requestHandle,
|
||||
responseType, UA_STATUSCODE_BADSECURITYPOLICYREJECTED);
|
||||
UA_STATUSCODE_BADSECURITYPOLICYREJECTED);
|
||||
goto update_statistics;
|
||||
}
|
||||
|
||||
@ -596,13 +601,14 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques
|
||||
/* Get the Session bound to the SecureChannel (not necessarily activated) */
|
||||
if(!UA_NodeId_isNull(&requestHeader->authenticationToken)) {
|
||||
UA_LOCK(&server->serviceMutex);
|
||||
UA_StatusCode retval = getBoundSession(
|
||||
server, channel, &requestHeader->authenticationToken, &session);
|
||||
UA_StatusCode retval =
|
||||
getBoundSession(server, channel,
|
||||
&requestHeader->authenticationToken, &session);
|
||||
UA_UNLOCK(&server->serviceMutex);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
serviceRes = response->responseHeader.serviceResult;
|
||||
channelRes = sendServiceFault(channel, requestId, requestHeader->requestHandle,
|
||||
responseType, retval);
|
||||
channelRes = sendServiceFault(channel, requestId,
|
||||
requestHeader->requestHandle, retval);
|
||||
goto update_statistics;
|
||||
}
|
||||
}
|
||||
@ -622,7 +628,7 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques
|
||||
#endif
|
||||
serviceRes = UA_STATUSCODE_BADSESSIONIDINVALID;
|
||||
channelRes = sendServiceFault(channel, requestId, requestHeader->requestHandle,
|
||||
responseType, UA_STATUSCODE_BADSESSIONIDINVALID);
|
||||
UA_STATUSCODE_BADSESSIONIDINVALID);
|
||||
goto update_statistics;
|
||||
}
|
||||
|
||||
@ -653,7 +659,7 @@ processMSGDecoded(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 reques
|
||||
}
|
||||
serviceRes = UA_STATUSCODE_BADSESSIONNOTACTIVATED;
|
||||
channelRes = sendServiceFault(channel, requestId, requestHeader->requestHandle,
|
||||
responseType, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
|
||||
UA_STATUSCODE_BADSESSIONNOTACTIVATED);
|
||||
goto update_statistics;
|
||||
}
|
||||
|
||||
@ -786,7 +792,7 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
|
||||
"See the 'verifyRequestTimestamp' setting.");
|
||||
if(server->config.verifyRequestTimestamp <= UA_RULEHANDLING_ABORT) {
|
||||
retval = sendServiceFault(channel, requestId, requestHeader->requestHandle,
|
||||
responseType, UA_STATUSCODE_BADINVALIDTIMESTAMP);
|
||||
UA_STATUSCODE_BADINVALIDTIMESTAMP);
|
||||
UA_clear(&request, requestType);
|
||||
return retval;
|
||||
}
|
||||
|
@ -104,6 +104,7 @@ struct UA_Server {
|
||||
/* Session Management */
|
||||
LIST_HEAD(session_list, session_list_entry) sessions;
|
||||
UA_UInt32 sessionCount;
|
||||
UA_UInt32 activeSessionCount;
|
||||
UA_Session adminSession; /* Local access to the services (for startup and
|
||||
* maintenance) uses this Session with all possible
|
||||
* access rights (Session Id: 1) */
|
||||
@ -183,8 +184,8 @@ UA_Server_configSecureChannel(void *application, UA_SecureChannel *channel,
|
||||
const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);
|
||||
|
||||
UA_StatusCode
|
||||
sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId, UA_UInt32 requestHandle,
|
||||
const UA_DataType *responseType, UA_StatusCode statusCode);
|
||||
sendServiceFault(UA_SecureChannel *channel, UA_UInt32 requestId,
|
||||
UA_UInt32 requestHandle, UA_StatusCode statusCode);
|
||||
|
||||
void
|
||||
UA_Server_closeSecureChannel(UA_Server *server, UA_SecureChannel *channel,
|
||||
|
@ -516,6 +516,8 @@ readDiagnostics(UA_Server *server, const UA_NodeId *sessionId, void *sessionCont
|
||||
|
||||
switch(nodeId->identifier.numeric) {
|
||||
case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY:
|
||||
server->serverDiagnosticsSummary.currentSessionCount =
|
||||
server->activeSessionCount;
|
||||
data = &server->serverDiagnosticsSummary;
|
||||
type = &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE];
|
||||
break;
|
||||
@ -523,7 +525,7 @@ readDiagnostics(UA_Server *server, const UA_NodeId *sessionId, void *sessionCont
|
||||
data = &server->serverDiagnosticsSummary.serverViewCount;
|
||||
break;
|
||||
case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSESSIONCOUNT:
|
||||
data = &server->serverDiagnosticsSummary.currentSessionCount;
|
||||
data = &server->activeSessionCount;
|
||||
break;
|
||||
case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSESSIONCOUNT:
|
||||
data = &server->serverDiagnosticsSummary.cumulatedSessionCount;
|
||||
|
@ -252,6 +252,12 @@ Service_GetEndpoints(UA_Server *server, UA_Session *session,
|
||||
for(size_t i = 0; i < clone_times; ++i) {
|
||||
retval |= UA_EndpointDescription_copy(&server->config.endpoints[j],
|
||||
&response->endpoints[pos]);
|
||||
UA_String_clear(&response->endpoints[pos].endpointUrl);
|
||||
UA_Array_delete(response->endpoints[pos].server.discoveryUrls,
|
||||
response->endpoints[pos].server.discoveryUrlsSize,
|
||||
&UA_TYPES[UA_TYPES_STRING]);
|
||||
response->endpoints[pos].server.discoveryUrls = NULL;
|
||||
response->endpoints[pos].server.discoveryUrlsSize = 0;
|
||||
if(nl_endpointurl)
|
||||
endpointUrl = &server->config.networkLayers[i].discoveryUrl;
|
||||
retval |= UA_String_copy(endpointUrl, &response->endpoints[pos].endpointUrl);
|
||||
|
@ -42,7 +42,7 @@ setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session,
|
||||
browseSimplifiedBrowsePath(server, mon->itemToMonitor.nodeId, 1, &qn);
|
||||
if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
|
||||
UA_BrowsePathResult_clear(&bpr);
|
||||
return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
|
||||
return UA_STATUSCODE_BADFILTERNOTALLOWED;
|
||||
}
|
||||
|
||||
/* Read the range */
|
||||
@ -56,7 +56,7 @@ setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session,
|
||||
if(!UA_Variant_isScalar(&rangeVal.value) ||
|
||||
rangeVal.value.type != &UA_TYPES[UA_TYPES_RANGE]) {
|
||||
UA_DataValue_clear(&rangeVal);
|
||||
return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
|
||||
return UA_STATUSCODE_BADFILTERNOTALLOWED;
|
||||
}
|
||||
|
||||
/* Compute the abs deadband */
|
||||
@ -68,7 +68,7 @@ setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session,
|
||||
/* EURange invalid or NaN? */
|
||||
if(absDeadband < 0.0 || absDeadband != absDeadband) {
|
||||
UA_DataValue_clear(&rangeVal);
|
||||
return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
|
||||
return UA_STATUSCODE_BADFILTERNOTALLOWED;
|
||||
}
|
||||
|
||||
/* Adjust the original filter */
|
||||
|
@ -57,13 +57,15 @@ UA_Server_removeSession(UA_Server *server, session_list_entry *sentry,
|
||||
UA_Session_detachFromSecureChannel(session);
|
||||
|
||||
/* Deactivate the session */
|
||||
sentry->session.activated = false;
|
||||
if(sentry->session.activated) {
|
||||
sentry->session.activated = false;
|
||||
server->activeSessionCount--;
|
||||
}
|
||||
|
||||
/* Detach the session from the session manager and make the capacity
|
||||
* available */
|
||||
LIST_REMOVE(sentry, pointers);
|
||||
server->sessionCount--;
|
||||
server->serverDiagnosticsSummary.currentSessionCount--;
|
||||
|
||||
switch(event) {
|
||||
case UA_DIAGNOSTICEVENT_CLOSE:
|
||||
@ -217,31 +219,36 @@ UA_Server_createSession(UA_Server *server, UA_SecureChannel *channel,
|
||||
const UA_CreateSessionRequest *request, UA_Session **session) {
|
||||
UA_LOCK_ASSERT(&server->serviceMutex, 1);
|
||||
|
||||
if(server->sessionCount >= server->config.maxSessions)
|
||||
if(server->sessionCount >= server->config.maxSessions) {
|
||||
UA_LOG_WARNING_CHANNEL(&server->config.logger, channel,
|
||||
"Could not create a Session - Server limits reached");
|
||||
return UA_STATUSCODE_BADTOOMANYSESSIONS;
|
||||
}
|
||||
|
||||
session_list_entry *newentry = (session_list_entry*)
|
||||
UA_malloc(sizeof(session_list_entry));
|
||||
if(!newentry)
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
|
||||
UA_atomic_addUInt32(&server->sessionCount, 1);
|
||||
/* Initialize the Session */
|
||||
UA_Session_init(&newentry->session);
|
||||
newentry->session.sessionId = UA_NODEID_GUID(1, UA_Guid_random());
|
||||
newentry->session.header.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random());
|
||||
|
||||
newentry->session.timeout = server->config.maxSessionTimeout;
|
||||
if(request->requestedSessionTimeout <= server->config.maxSessionTimeout &&
|
||||
request->requestedSessionTimeout > 0)
|
||||
newentry->session.timeout = request->requestedSessionTimeout;
|
||||
else
|
||||
newentry->session.timeout = server->config.maxSessionTimeout;
|
||||
|
||||
/* Attach the session to the channel. But don't activate for now. */
|
||||
if(channel)
|
||||
UA_Session_attachToSecureChannel(&newentry->session, channel);
|
||||
UA_Session_updateLifetime(&newentry->session);
|
||||
|
||||
/* Add to the server */
|
||||
LIST_INSERT_HEAD(&server->sessions, newentry, pointers);
|
||||
server->sessionCount++;
|
||||
|
||||
*session = &newentry->session;
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
@ -843,7 +850,7 @@ Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
|
||||
/* Activate the session */
|
||||
if(!session->activated) {
|
||||
session->activated = true;
|
||||
server->serverDiagnosticsSummary.currentSessionCount++;
|
||||
server->activeSessionCount++;
|
||||
server->serverDiagnosticsSummary.cumulatedSessionCount++;
|
||||
}
|
||||
|
||||
|
@ -237,7 +237,6 @@ Service_Publish(UA_Server *server, UA_Session *session,
|
||||
if(TAILQ_EMPTY(&session->subscriptions)) {
|
||||
sendServiceFault(session->header.channel, requestId,
|
||||
request->requestHeader.requestHandle,
|
||||
&UA_TYPES[UA_TYPES_PUBLISHRESPONSE],
|
||||
UA_STATUSCODE_BADNOSUBSCRIPTION);
|
||||
return UA_STATUSCODE_BADNOSUBSCRIPTION;
|
||||
}
|
||||
@ -250,7 +249,6 @@ Service_Publish(UA_Server *server, UA_Session *session,
|
||||
if(!UA_Session_reachedPublishReqLimit(server, session)) {
|
||||
sendServiceFault(session->header.channel, requestId,
|
||||
request->requestHeader.requestHandle,
|
||||
&UA_TYPES[UA_TYPES_PUBLISHRESPONSE],
|
||||
UA_STATUSCODE_BADINTERNALERROR);
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
}
|
||||
@ -262,7 +260,6 @@ Service_Publish(UA_Server *server, UA_Session *session,
|
||||
if(!entry) {
|
||||
sendServiceFault(session->header.channel, requestId,
|
||||
request->requestHeader.requestHandle,
|
||||
&UA_TYPES[UA_TYPES_PUBLISHRESPONSE],
|
||||
UA_STATUSCODE_BADOUTOFMEMORY);
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
}
|
||||
@ -282,7 +279,6 @@ Service_Publish(UA_Server *server, UA_Session *session,
|
||||
UA_free(entry);
|
||||
sendServiceFault(session->header.channel, requestId,
|
||||
request->requestHeader.requestHandle,
|
||||
&UA_TYPES[UA_TYPES_PUBLISHRESPONSE],
|
||||
UA_STATUSCODE_BADOUTOFMEMORY);
|
||||
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||||
}
|
||||
|
@ -1322,10 +1322,7 @@ browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
|
||||
bp.relativePath.elementsSize = browsePathSize;
|
||||
|
||||
/* Browse */
|
||||
UA_UInt32 nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE;
|
||||
#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
|
||||
nodeClassMask |= UA_NODECLASS_OBJECTTYPE;
|
||||
#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */
|
||||
UA_UInt32 nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_OBJECTTYPE;
|
||||
|
||||
Operation_TranslateBrowsePathToNodeIds(server, &server->adminSession, &nodeClassMask, &bp, &bpr);
|
||||
return bpr;
|
||||
|
@ -316,6 +316,50 @@ implicitNumericVariantTransformation(UA_Variant *variant, void *data){
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
implicitNumericVariantTransformationUnsingedToSigned(UA_Variant *variant, void *data){
|
||||
if(variant->type == &UA_TYPES[UA_TYPES_UINT64]){
|
||||
if(*(UA_UInt64 *)variant->data > UA_INT64_MAX)
|
||||
return UA_STATUSCODE_BADTYPEMISMATCH;
|
||||
*(UA_Int64 *)data = *(UA_Int64 *)variant->data;
|
||||
UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]);
|
||||
} else if(variant->type == &UA_TYPES[UA_TYPES_UINT32]){
|
||||
*(UA_Int64 *)data = *(UA_Int32 *)variant->data;
|
||||
UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]);
|
||||
} else if(variant->type == &UA_TYPES[UA_TYPES_UINT16]){
|
||||
*(UA_Int64 *)data = *(UA_Int16 *)variant->data;
|
||||
UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]);
|
||||
} else if(variant->type == &UA_TYPES[UA_TYPES_BYTE]){
|
||||
*(UA_Int64 *)data = *(UA_Byte *)variant->data;
|
||||
UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT64]);
|
||||
} else {
|
||||
return UA_STATUSCODE_BADTYPEMISMATCH;
|
||||
}
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
implicitNumericVariantTransformationSignedToUnSigned(UA_Variant *variant, void *data){
|
||||
if(*(UA_Int64 *)variant->data < 0)
|
||||
return UA_STATUSCODE_BADTYPEMISMATCH;
|
||||
if(variant->type == &UA_TYPES[UA_TYPES_INT64]){
|
||||
*(UA_UInt64 *)data = *(UA_UInt64 *)variant->data;
|
||||
UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]);
|
||||
} else if(variant->type == &UA_TYPES[UA_TYPES_INT32]){
|
||||
*(UA_UInt64 *)data = *(UA_UInt32 *)variant->data;
|
||||
UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]);
|
||||
} else if(variant->type == &UA_TYPES[UA_TYPES_INT16]){
|
||||
*(UA_UInt64 *)data = *(UA_UInt16 *)variant->data;
|
||||
UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]);
|
||||
} else if(variant->type == &UA_TYPES[UA_TYPES_SBYTE]){
|
||||
*(UA_UInt64 *)data = *(UA_Byte *)variant->data;
|
||||
UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_UINT64]);
|
||||
} else {
|
||||
return UA_STATUSCODE_BADTYPEMISMATCH;
|
||||
}
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
/* 0 -> Same Type, 1 -> Implicit Cast, 2 -> Only explicit Cast, -1 -> cast invalid */
|
||||
static UA_SByte convertLookup[21][21] = {
|
||||
{ 0, 1,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 1,-1, 2,-1,-1, 1, 1, 1,-1},
|
||||
@ -416,7 +460,9 @@ compareOperation(UA_Variant *firstOperand, UA_Variant *secondOperand, UA_FilterO
|
||||
UA_TYPES_DIFFERENT_NUMERIC_FLOATING_POINT,
|
||||
UA_TYPES_DIFFERENT_TEXT,
|
||||
UA_TYPES_DIFFERENT_COMPARE_FORBIDDEN,
|
||||
UA_TYPES_DIFFERENT_COMPARE_EXPLIC
|
||||
UA_TYPES_DIFFERENT_COMPARE_EXPLIC,
|
||||
UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_SIGNED,
|
||||
UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_UNSIGNED
|
||||
} compareHandlingRuleEnum;
|
||||
|
||||
if(castRule == 0 &&
|
||||
@ -445,6 +491,14 @@ compareOperation(UA_Variant *firstOperand, UA_Variant *secondOperand, UA_FilterO
|
||||
isStringType(firstOperand->type->typeKind)&&
|
||||
isStringType(secondOperand->type->typeKind)){
|
||||
compareHandlingRuleEnum = UA_TYPES_DIFFERENT_TEXT;
|
||||
} else if(castRule == 1 &&
|
||||
isNumericSigned(firstOperand->type->typeKind) &&
|
||||
isNumericUnsigned(secondOperand->type->typeKind)){
|
||||
compareHandlingRuleEnum = UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_SIGNED;
|
||||
} else if(castRule == 1 &&
|
||||
isNumericSigned(secondOperand->type->typeKind) &&
|
||||
isNumericUnsigned(firstOperand->type->typeKind)){
|
||||
compareHandlingRuleEnum = UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_UNSIGNED;
|
||||
} else if(castRule == -1 || castRule == 2){
|
||||
compareHandlingRuleEnum = UA_TYPES_DIFFERENT_COMPARE_EXPLIC;
|
||||
} else {
|
||||
@ -467,6 +521,12 @@ compareOperation(UA_Variant *firstOperand, UA_Variant *secondOperand, UA_FilterO
|
||||
compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_FLOATING_POINT) {
|
||||
implicitNumericVariantTransformation(firstCompareOperand, variantContent);
|
||||
implicitNumericVariantTransformation(secondCompareOperand, &variantContent[8]);
|
||||
} else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_SIGNED) {
|
||||
implicitNumericVariantTransformation(firstCompareOperand, variantContent);
|
||||
implicitNumericVariantTransformationUnsingedToSigned(secondCompareOperand, &variantContent[8]);
|
||||
} else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_UNSIGNED) {
|
||||
implicitNumericVariantTransformation(firstCompareOperand, variantContent);
|
||||
implicitNumericVariantTransformationSignedToUnSigned(secondCompareOperand, &variantContent[8]);
|
||||
} else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_TEXT) {
|
||||
firstCompareOperand->type = &UA_TYPES[UA_TYPES_STRING];
|
||||
secondCompareOperand->type = &UA_TYPES[UA_TYPES_STRING];
|
||||
@ -479,12 +539,18 @@ compareOperation(UA_Variant *firstOperand, UA_Variant *secondOperand, UA_FilterO
|
||||
}
|
||||
} else {
|
||||
UA_Byte variantContent[16];
|
||||
memset(&variantContent, 0, sizeof(UA_Byte) * 16);
|
||||
if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_SIGNED ||
|
||||
compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_UNSIGNED ||
|
||||
compareHandlingRuleEnum == UA_TYPES_DIFFERENT_NUMERIC_FLOATING_POINT) {
|
||||
memset(&variantContent, 0, sizeof(UA_Byte) * 16);
|
||||
implicitNumericVariantTransformation(firstCompareOperand, variantContent);
|
||||
implicitNumericVariantTransformation(secondCompareOperand, &variantContent[8]);
|
||||
} else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_SIGNED) {
|
||||
implicitNumericVariantTransformation(firstCompareOperand, variantContent);
|
||||
implicitNumericVariantTransformationUnsingedToSigned(secondCompareOperand, &variantContent[8]);
|
||||
} else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_SIGNEDNESS_CAST_TO_UNSIGNED) {
|
||||
implicitNumericVariantTransformation(firstCompareOperand, variantContent);
|
||||
implicitNumericVariantTransformationSignedToUnSigned(secondCompareOperand, &variantContent[8]);
|
||||
} else if(compareHandlingRuleEnum == UA_TYPES_DIFFERENT_TEXT) {
|
||||
firstCompareOperand->type = &UA_TYPES[UA_TYPES_STRING];
|
||||
secondCompareOperand->type = &UA_TYPES[UA_TYPES_STRING];
|
||||
@ -1033,6 +1099,41 @@ UA_Event_staticSelectClauseValidation(UA_Server *server,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the list of Subtypes from current node */
|
||||
UA_ReferenceTypeSet reftypes_interface =
|
||||
UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
|
||||
UA_ExpandedNodeId *chilTypeNodes = NULL;
|
||||
size_t chilTypeNodesSize = 0;
|
||||
UA_StatusCode res;
|
||||
res = browseRecursive(server, 1, &eventFilter->selectClauses[i].typeDefinitionId,
|
||||
UA_BROWSEDIRECTION_FORWARD, &reftypes_interface, UA_NODECLASS_OBJECTTYPE,
|
||||
true, &chilTypeNodesSize, &chilTypeNodes);
|
||||
if(res!=UA_STATUSCODE_GOOD){
|
||||
result[i] = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
|
||||
continue;
|
||||
}
|
||||
|
||||
UA_Boolean subTypeContainField = false;
|
||||
for (size_t j = 0; j < chilTypeNodesSize; ++j) {
|
||||
/* browsPath element is defined in path */
|
||||
UA_BrowsePathResult bpr =
|
||||
browseSimplifiedBrowsePath(server, chilTypeNodes[j].nodeId,
|
||||
eventFilter->selectClauses[i].browsePathSize,
|
||||
eventFilter->selectClauses[i].browsePath);
|
||||
|
||||
if(bpr.statusCode != UA_STATUSCODE_GOOD){
|
||||
UA_BrowsePathResult_clear(&bpr);
|
||||
continue;
|
||||
}
|
||||
subTypeContainField = true;
|
||||
UA_BrowsePathResult_clear(&bpr);
|
||||
}
|
||||
if(!subTypeContainField)
|
||||
result[i] = UA_STATUSCODE_BADNODEIDUNKNOWN;
|
||||
|
||||
UA_Array_delete(chilTypeNodes, chilTypeNodesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
|
||||
|
||||
if(result[i] != UA_STATUSCODE_GOOD)
|
||||
continue;
|
||||
/*indexRange is defined ? */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -50,19 +50,6 @@ UA_encodeJsonInternal(const void *src, const UA_DataType *type, uint8_t **bufPos
|
||||
size_t serverUriSize,
|
||||
UA_Boolean useReversible) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/* Decodes a scalar value described by type from json encoding.
|
||||
*
|
||||
* @param src The buffer with the json encoded value. Must not be NULL.
|
||||
* @param dst The target value. Must not be NULL. The target is assumed to have
|
||||
* size type->memSize. The value is reset to zero before decoding. If
|
||||
* decoding fails, members are deleted and the value is reset (zeroed)
|
||||
* again.
|
||||
* @param type The value type. Must not be NULL.
|
||||
* @return Returns a statuscode whether decoding succeeded. */
|
||||
UA_StatusCode
|
||||
UA_decodeJsonInternal(const UA_ByteString *src, void *dst,
|
||||
const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/* Interal Definitions
|
||||
*
|
||||
* For future by the PubSub encoding */
|
||||
@ -150,43 +137,49 @@ typedef struct {
|
||||
size_t numCustom;
|
||||
void * custom;
|
||||
size_t currentCustomIndex;
|
||||
|
||||
const UA_DataTypeArray *customTypes;
|
||||
} ParseCtx;
|
||||
|
||||
typedef UA_StatusCode
|
||||
(*encodeJsonSignature)(const void *src, const UA_DataType *type, CtxJson *ctx);
|
||||
|
||||
typedef UA_StatusCode
|
||||
(*decodeJsonSignature)(void *dst, const UA_DataType *type, CtxJson *ctx,
|
||||
ParseCtx *parseCtx, UA_Boolean moveToken);
|
||||
(*decodeJsonSignature)(void *dst, const UA_DataType *type,
|
||||
CtxJson *ctx, ParseCtx *parseCtx);
|
||||
|
||||
/* Map for decoding a Json Object. An array of this is passed to the
|
||||
* decodeFields function. If the key "fieldName" is found in the json object
|
||||
* (mark as found and) decode the value with the "function" and write result
|
||||
* into "fieldPointer" (destination). */
|
||||
typedef struct {
|
||||
const char * fieldName;
|
||||
void * fieldPointer;
|
||||
const char *fieldName;
|
||||
void *fieldPointer;
|
||||
decodeJsonSignature function;
|
||||
UA_Boolean found;
|
||||
const UA_DataType *type;
|
||||
const UA_DataType *type; /* Must be set for values that can be "null". If
|
||||
* the function is not set, decode via the
|
||||
* type->typeKind. */
|
||||
} DecodeEntry;
|
||||
|
||||
UA_StatusCode
|
||||
decodeFields(CtxJson *ctx, ParseCtx *parseCtx,
|
||||
DecodeEntry *entries, size_t entryCount,
|
||||
const UA_DataType *type);
|
||||
DecodeEntry *entries, size_t entryCount);
|
||||
|
||||
UA_StatusCode
|
||||
decodeJsonInternal(void *dst, const UA_DataType *type,
|
||||
CtxJson *ctx, ParseCtx *parseCtx, UA_Boolean moveToken);
|
||||
/* Expose the jump tables and some methods for PubSub JSON decoding */
|
||||
extern const encodeJsonSignature encodeJsonJumpTable[UA_DATATYPEKINDS];
|
||||
extern const decodeJsonSignature decodeJsonJumpTable[UA_DATATYPEKINDS];
|
||||
|
||||
/* workaround: TODO generate functions for UA_xxx_decodeJson */
|
||||
decodeJsonSignature getDecodeSignature(u8 index);
|
||||
UA_StatusCode lookAheadForKey(const char* search, CtxJson *ctx, ParseCtx *parseCtx, size_t *resultIndex);
|
||||
jsmntype_t getJsmnType(const ParseCtx *parseCtx);
|
||||
UA_StatusCode lookAheadForKey(const char* search, CtxJson *ctx,
|
||||
ParseCtx *parseCtx, size_t *resultIndex);
|
||||
UA_StatusCode tokenize(ParseCtx *parseCtx, CtxJson *ctx, const UA_ByteString *src);
|
||||
UA_Boolean isJsonNull(const CtxJson *ctx, const ParseCtx *parseCtx);
|
||||
|
||||
static UA_INLINE
|
||||
jsmntype_t getJsmnType(const ParseCtx *parseCtx) {
|
||||
return parseCtx->tokenArray[parseCtx->index].type;
|
||||
}
|
||||
|
||||
_UA_END_DECLS
|
||||
|
||||
#endif /* UA_TYPES_ENCODING_JSON_H_ */
|
||||
|
@ -20,6 +20,11 @@
|
||||
# pragma warning(disable: 4146)
|
||||
#endif
|
||||
|
||||
static UA_INLINE UA_StatusCode
|
||||
UA_decodeJsonInternal(const UA_ByteString *src, void *dst, const UA_DataType *type) {
|
||||
return UA_decodeJson(src, dst, type, NULL);
|
||||
}
|
||||
|
||||
/* Test Boolean */
|
||||
START_TEST(UA_Boolean_true_json_encode) {
|
||||
|
||||
@ -1417,7 +1422,7 @@ START_TEST(UA_StatusCode_nonReversible_good_json_encode) {
|
||||
|
||||
// then
|
||||
ck_assert_int_eq(s, UA_STATUSCODE_GOOD);
|
||||
char* result = "null";
|
||||
char* result = "{\"Code\":0,\"Symbol\":\"Good\"}";
|
||||
ck_assert_str_eq(result, (char*)buf.data);
|
||||
UA_ByteString_clear(&buf);
|
||||
UA_StatusCode_delete(src);
|
||||
@ -1863,7 +1868,7 @@ START_TEST(UA_DiagInfo_noFields_json_encode) {
|
||||
*bufPos = 0;
|
||||
// then
|
||||
ck_assert_int_eq(s, UA_STATUSCODE_GOOD);
|
||||
char* result = "null";
|
||||
char* result = "{}";
|
||||
ck_assert_str_eq(result, (char*)buf.data);
|
||||
UA_ByteString_clear(&buf);
|
||||
UA_DiagnosticInfo_delete(src);
|
||||
@ -1900,7 +1905,6 @@ START_TEST(UA_DiagInfo_smallBuffer_json_encode) {
|
||||
|
||||
status s = UA_encodeJsonInternal((void *) src, type, &bufPos, &bufEnd, NULL, 0, NULL, 0, true);
|
||||
|
||||
*bufPos = 0;
|
||||
// then
|
||||
ck_assert_int_eq(s, UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
|
||||
UA_ByteString_clear(&buf);
|
||||
@ -2511,6 +2515,34 @@ START_TEST(UA_Variant_Array_UInt16_json_encode) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(UA_Variant_Array_UInt16_Null_json_encode) {
|
||||
UA_Variant *src = UA_Variant_new();
|
||||
UA_Variant_init(src);
|
||||
UA_Variant_setArray(src, NULL, 0, &UA_TYPES[UA_TYPES_UINT16]);
|
||||
|
||||
const UA_DataType *type = &UA_TYPES[UA_TYPES_VARIANT];
|
||||
size_t size = UA_calcSizeJsonInternal((void *) src, type, NULL, 0, NULL, 0, true);
|
||||
UA_ByteString buf;
|
||||
|
||||
UA_ByteString_allocBuffer(&buf, size+1);
|
||||
|
||||
UA_Byte *bufPos = &buf.data[0];
|
||||
const UA_Byte *bufEnd = &buf.data[size+1];
|
||||
|
||||
status s = UA_encodeJsonInternal((void *) src, type, &bufPos, &bufEnd, NULL, 0, NULL, 0, true);
|
||||
ck_assert_int_eq(s, UA_STATUSCODE_GOOD);
|
||||
|
||||
*bufPos = 0;
|
||||
// then
|
||||
ck_assert_int_eq(s, UA_STATUSCODE_GOOD);
|
||||
char* result = "{\"Type\":5,\"Body\":[]}";
|
||||
ck_assert_str_eq(result, (char*)buf.data);
|
||||
|
||||
UA_ByteString_clear(&buf);
|
||||
UA_Variant_delete(src);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(UA_Variant_Array_Byte_json_encode) {
|
||||
UA_Variant *src = UA_Variant_new();
|
||||
UA_Variant_init(src);
|
||||
@ -3212,7 +3244,7 @@ START_TEST(UA_DataValue_null_json_encode) {
|
||||
*bufPos = 0;
|
||||
// then
|
||||
ck_assert_int_eq(s, UA_STATUSCODE_GOOD);
|
||||
char* result = "null";
|
||||
char* result = "{}";
|
||||
ck_assert_str_eq(result, (char*)buf.data);
|
||||
UA_ByteString_clear(&buf);
|
||||
UA_DataValue_delete(src);
|
||||
@ -4347,7 +4379,7 @@ END_TEST
|
||||
START_TEST(UA_ByteString_bad_json_decode) {
|
||||
UA_ByteString out;
|
||||
UA_ByteString_init(&out);
|
||||
UA_ByteString buf = UA_STRING("\"\x90!\xc5 c{\",");
|
||||
UA_ByteString buf = UA_STRING("\"\x90!\xc5 c{\"");
|
||||
// when
|
||||
|
||||
UA_StatusCode retval = UA_decodeJsonInternal(&buf, &out, &UA_TYPES[UA_TYPES_BYTESTRING]);
|
||||
@ -4364,9 +4396,6 @@ START_TEST(UA_ByteString_null_json_decode) {
|
||||
UA_StatusCode retval = UA_decodeJsonInternal(&buf, &out, &UA_TYPES[UA_TYPES_VARIANT]);
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
ck_assert_int_eq(out.type->typeKind, UA_DATATYPEKIND_BYTESTRING);
|
||||
UA_ByteString *outData = (UA_ByteString*)out.data;
|
||||
ck_assert_ptr_ne(outData, NULL);
|
||||
ck_assert_ptr_eq(outData->data, NULL);
|
||||
UA_Variant_clear(&out);
|
||||
}
|
||||
END_TEST
|
||||
@ -4620,7 +4649,6 @@ START_TEST(UA_QualifiedName_null_json_decode) {
|
||||
UA_StatusCode retval = UA_decodeJsonInternal(&buf, &out, &UA_TYPES[UA_TYPES_VARIANT]);
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
ck_assert_int_eq(out.type->typeKind, UA_DATATYPEKIND_QUALIFIEDNAME);
|
||||
ck_assert_ptr_ne(out.data, NULL);
|
||||
UA_Variant_clear(&out);
|
||||
}
|
||||
END_TEST
|
||||
@ -4671,7 +4699,6 @@ START_TEST(UA_LocalizedText_null_json_decode) {
|
||||
UA_StatusCode retval = UA_decodeJsonInternal(&buf, &out, &UA_TYPES[UA_TYPES_VARIANT]);
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
ck_assert_int_eq(out.type->typeKind, UA_DATATYPEKIND_LOCALIZEDTEXT);
|
||||
ck_assert_ptr_ne(out.data, NULL);
|
||||
UA_Variant_clear(&out);
|
||||
}
|
||||
END_TEST
|
||||
@ -5016,13 +5043,6 @@ START_TEST(UA_DiagnosticInfo_null_json_decode) {
|
||||
UA_StatusCode retval = UA_decodeJsonInternal(&buf, &out, &UA_TYPES[UA_TYPES_VARIANT]);
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
ck_assert_int_eq(out.type->typeKind, UA_DATATYPEKIND_DIAGNOSTICINFO);
|
||||
ck_assert_uint_eq(((UA_DiagnosticInfo*)out.data)->hasAdditionalInfo, 0);
|
||||
ck_assert_uint_eq(((UA_DiagnosticInfo*)out.data)->hasInnerDiagnosticInfo, 0);
|
||||
ck_assert_uint_eq(((UA_DiagnosticInfo*)out.data)->hasInnerStatusCode, 0);
|
||||
ck_assert_uint_eq(((UA_DiagnosticInfo*)out.data)->hasLocale, 0);
|
||||
ck_assert_uint_eq(((UA_DiagnosticInfo*)out.data)->hasLocalizedText, 0);
|
||||
ck_assert_uint_eq(((UA_DiagnosticInfo*)out.data)->hasNamespaceUri, 0);
|
||||
ck_assert_uint_eq(((UA_DiagnosticInfo*)out.data)->hasSymbolicId, 0);
|
||||
UA_Variant_clear(&out);
|
||||
}
|
||||
END_TEST
|
||||
@ -5086,7 +5106,6 @@ START_TEST(UA_DataValue_null_json_decode) {
|
||||
UA_ByteString buf = UA_STRING("{\"Type\":23,\"Body\":null}");
|
||||
UA_StatusCode retval = UA_decodeJsonInternal(&buf, &out, &UA_TYPES[UA_TYPES_VARIANT]);
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
ck_assert_ptr_ne(out.data, NULL);
|
||||
UA_Variant_clear(&out);
|
||||
}
|
||||
END_TEST
|
||||
@ -5217,7 +5236,7 @@ START_TEST(UA_VariantBoolNull_json_decode) {
|
||||
|
||||
UA_StatusCode retval = UA_decodeJsonInternal(&buf, &out, &UA_TYPES[UA_TYPES_VARIANT]);
|
||||
// then
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_BADDECODINGERROR);
|
||||
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
|
||||
UA_Variant_clear(&out);
|
||||
}
|
||||
END_TEST
|
||||
@ -5844,6 +5863,7 @@ static Suite *testSuite_builtin_json(void) {
|
||||
|
||||
//Array
|
||||
tcase_add_test(tc_json_encode, UA_Variant_Array_UInt16_json_encode);
|
||||
tcase_add_test(tc_json_encode, UA_Variant_Array_UInt16_Null_json_encode);
|
||||
tcase_add_test(tc_json_encode, UA_Variant_Array_Byte_json_encode);
|
||||
tcase_add_test(tc_json_encode, UA_Variant_Array_String_json_encode);
|
||||
|
||||
|
@ -24,6 +24,7 @@ LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
|
||||
return 0;
|
||||
|
||||
size_t jsonSize = UA_calcSizeJson(&value, &UA_TYPES[UA_TYPES_VARIANT], NULL);
|
||||
UA_assert(jsonSize > 0); /* 0 => fail */
|
||||
|
||||
UA_ByteString buf2 = UA_BYTESTRING_NULL;
|
||||
retval = UA_ByteString_allocBuffer(&buf2, jsonSize);
|
||||
@ -38,18 +39,15 @@ LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
|
||||
UA_Variant value2;
|
||||
UA_Variant_init(&value2);
|
||||
retval = UA_decodeJson(&buf2, &value2, &UA_TYPES[UA_TYPES_VARIANT], NULL);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
UA_Variant_clear(&value);
|
||||
UA_ByteString_clear(&buf2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UA_assert(UA_order(&value, &value2, &UA_TYPES[UA_TYPES_VARIANT]) == UA_ORDER_EQ);
|
||||
UA_Variant_clear(&value);
|
||||
UA_assert(retval == UA_STATUSCODE_GOOD);
|
||||
/* TODO: Enable this assertion when the binary-JSON-binary roundtrip is complete.
|
||||
* Waiting for Mantis issue #7750.
|
||||
* UA_assert(UA_order(&value, &value2, &UA_TYPES[UA_TYPES_VARIANT]) == UA_ORDER_EQ); */
|
||||
|
||||
UA_ByteString buf3 = UA_BYTESTRING_NULL;
|
||||
retval = UA_ByteString_allocBuffer(&buf3, jsonSize);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
UA_Variant_clear(&value);
|
||||
UA_Variant_clear(&value2);
|
||||
UA_ByteString_clear(&buf2);
|
||||
return 0;
|
||||
@ -61,6 +59,7 @@ LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
|
||||
UA_assert(buf2.length == buf3.length);
|
||||
UA_assert(memcmp(buf2.data, buf3.data, buf2.length) == 0);
|
||||
|
||||
UA_Variant_clear(&value);
|
||||
UA_Variant_clear(&value2);
|
||||
UA_ByteString_clear(&buf2);
|
||||
UA_ByteString_clear(&buf3);
|
||||
|
@ -81,7 +81,7 @@ START_TEST(UA_PubSub_EncodeAllOptionalFields) {
|
||||
m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue = true;
|
||||
|
||||
size_t size = UA_NetworkMessage_calcSizeJson(&m, NULL, 0, NULL, 0, true);
|
||||
ck_assert_int_eq(size, 342);
|
||||
ck_assert_int_eq(size, 340);
|
||||
|
||||
UA_ByteString buffer;
|
||||
UA_StatusCode rv = UA_ByteString_allocBuffer(&buffer, size+1);
|
||||
@ -97,7 +97,7 @@ START_TEST(UA_PubSub_EncodeAllOptionalFields) {
|
||||
// then
|
||||
ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
|
||||
|
||||
char* result = "{\"MessageId\":\"ABCDEFGH\",\"MessageType\":\"ua-data\",\"PublisherId\":65535,\"DataSetClassId\":\"00000001-0002-0003-0000-000000000000\",\"Messages\":[{\"DataSetWriterId\":12345,\"SequenceNumber\":4711,\"MetaDataVersion\":{\"MajorVersion\":42,\"MinorVersion\":7},\"Timestamp\":\"1601-01-13T20:38:31.1111111Z\",\"Status\":2764857,\"Payload\":{\"Field1\":{\"Type\":7,\"Body\":27}}}]}";
|
||||
char* result = "{\"MessageId\":\"ABCDEFGH\",\"MessageType\":\"ua-data\",\"PublisherId\":65535,\"DataSetClassId\":\"00000001-0002-0003-0000-000000000000\",\"Messages\":[{\"DataSetWriterId\":12345,\"SequenceNumber\":4711,\"MetaDataVersion\":{\"MajorVersion\":42,\"MinorVersion\":7},\"Timestamp\":\"1601-01-13T20:38:31.1111111Z\",\"Status\":12345,\"Payload\":{\"Field1\":{\"Type\":7,\"Body\":27}}}]}";
|
||||
ck_assert_str_eq(result, (char*)buffer.data);
|
||||
|
||||
UA_ByteString_clear(&buffer);
|
||||
|
@ -602,7 +602,7 @@ START_TEST(Server_MonitoredItemsPercentFilterSetLaterMissingEURange) {
|
||||
ck_assert_uint_eq(modifyResponse.resultsSize, 1);
|
||||
/* missing EURange. See https://reference.opcfoundation.org/v104/Core/docs/Part8/6.2/ */
|
||||
ck_assert_uint_eq(modifyResponse.results[0].statusCode,
|
||||
UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED);
|
||||
UA_STATUSCODE_BADFILTERNOTALLOWED);
|
||||
|
||||
UA_ModifyMonitoredItemsResponse_clear(&modifyResponse);
|
||||
|
||||
@ -948,7 +948,7 @@ START_TEST(Server_MonitoredItemsPercentFilterSetOnCreateMissingEURange) {
|
||||
ck_assert_uint_eq(createResponse.resultsSize, 1);
|
||||
/* missing EURange. See https://reference.opcfoundation.org/v104/Core/docs/Part8/6.2/ */
|
||||
ck_assert_uint_eq(createResponse.results[0].statusCode,
|
||||
UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED);
|
||||
UA_STATUSCODE_BADFILTERNOTALLOWED);
|
||||
newMonitoredItemIds[0] = createResponse.results[0].monitoredItemId;
|
||||
UA_CreateMonitoredItemsResponse_clear(&createResponse);
|
||||
|
||||
|
@ -460,6 +460,39 @@ setupLiteralOperand(UA_ContentFilterElement *element, size_t count, UA_Variant *
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(selectFilterValidation) {
|
||||
/* setup event filter */
|
||||
UA_EventFilter filter;
|
||||
UA_EventFilter_init(&filter);
|
||||
filter.whereClause.elementsSize = 0;
|
||||
filter.whereClause.elements = NULL;
|
||||
filter.selectClauses = UA_SimpleAttributeOperand_new();
|
||||
filter.selectClausesSize = 1;
|
||||
UA_SimpleAttributeOperand_init(filter.selectClauses);
|
||||
filter.selectClauses->typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
|
||||
filter.selectClauses->browsePathSize = 1;
|
||||
filter.selectClauses->browsePath = (UA_QualifiedName*)
|
||||
UA_Array_new(filter.selectClauses->browsePathSize, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
|
||||
filter.selectClauses->attributeId = UA_ATTRIBUTEID_VALUE;
|
||||
|
||||
filter.selectClauses->browsePath[0] = UA_QUALIFIEDNAME_ALLOC(0, "FOOBAR");
|
||||
UA_MonitoredItemCreateResult createResult;
|
||||
createResult = addMonitoredItem(handler_events_simple, &filter, true);
|
||||
ck_assert_uint_eq(createResult.statusCode, UA_STATUSCODE_BADNODEIDUNKNOWN);
|
||||
UA_QualifiedName_clear(&filter.selectClauses->browsePath[0]);
|
||||
|
||||
filter.selectClauses->browsePath[0] = UA_QUALIFIEDNAME_ALLOC(0, "");
|
||||
createResult = addMonitoredItem(handler_events_simple, &filter, true);
|
||||
ck_assert_uint_eq(createResult.statusCode, UA_STATUSCODE_BADNODEIDUNKNOWN);
|
||||
|
||||
UA_QualifiedName_delete(&filter.selectClauses->browsePath[0]);
|
||||
filter.selectClauses->browsePath = NULL;
|
||||
filter.selectClauses->browsePathSize = 0;
|
||||
createResult = addMonitoredItem(handler_events_simple, &filter, true);
|
||||
ck_assert_uint_eq(createResult.statusCode, UA_STATUSCODE_BADBROWSENAMEINVALID);
|
||||
UA_EventFilter_clear(&filter);
|
||||
} END_TEST
|
||||
|
||||
/* Test Case "not-Operator" Description:
|
||||
Phase 1:
|
||||
Action -> Fire default "EventType_A_Layer_1" Event
|
||||
@ -775,6 +808,7 @@ static Suite *testSuite_Client(void) {
|
||||
Suite *s = suite_create("Server Subscription Event Filters");
|
||||
TCase *tc_server = tcase_create("Basic Event Filters");
|
||||
tcase_add_unchecked_fixture(tc_server, setup, teardown);
|
||||
tcase_add_test(tc_server, selectFilterValidation);
|
||||
tcase_add_test(tc_server, notOperatorValidation);
|
||||
tcase_add_test(tc_server, ofTypeOperatorValidation);
|
||||
tcase_add_test(tc_server, orTypeOperatorValidation);
|
||||
|
@ -109,7 +109,7 @@ os.system("""openssl req \
|
||||
-x509 -sha256 \
|
||||
-newkey rsa:{} \
|
||||
-keyout localhost.key -days 365 \
|
||||
-subj "/C=DE/O=open62541/CN=open62541Server@localhost"\
|
||||
-subj "/C=DE/L=Here/O=open62541/CN=open62541Server@localhost"\
|
||||
-out localhost.crt""".format(openssl_conf, keysize))
|
||||
os.system("openssl x509 -in localhost.crt -outform der -out %s_cert.der" % (certificatename))
|
||||
os.system("openssl rsa -inform PEM -in localhost.key -outform DER -out %s_key.der"% (certificatename))
|
||||
|
@ -2,7 +2,7 @@ from datatypes import Boolean, Byte, SByte, \
|
||||
Int16, UInt16, Int32, UInt32, Int64, UInt64, Float, Double, \
|
||||
String, XmlElement, ByteString, Structure, ExtensionObject, LocalizedText, \
|
||||
NodeId, ExpandedNodeId, DateTime, QualifiedName, StatusCode, \
|
||||
DiagnosticInfo, Guid, BuiltinType
|
||||
DiagnosticInfo, Guid, BuiltinType, EnumerationType
|
||||
import datetime
|
||||
import re
|
||||
|
||||
@ -121,7 +121,7 @@ def generateNodeValueCode(prepend , node, instanceName, valueName, global_var_co
|
||||
node.value = 0.0
|
||||
else:
|
||||
node.value = 0
|
||||
if encRule is None:
|
||||
if encRule is None or isinstance(encRule.member_type, EnumerationType):
|
||||
return prepend + " = (UA_" + node.__class__.__name__ + ") " + str(node.value) + ";"
|
||||
else:
|
||||
return prepend + " = (UA_" + encRule.member_type.name + ") " + str(node.value) + ";"
|
||||
@ -130,6 +130,10 @@ def generateNodeValueCode(prepend , node, instanceName, valueName, global_var_co
|
||||
elif isinstance(node, XmlElement):
|
||||
return prepend + " = " + generateXmlElementCode(node.value, alloc=asIndirect) + ";"
|
||||
elif isinstance(node, ByteString):
|
||||
# Basically the prepend must be passed to the generateByteStrongCode function so that the nested structures are
|
||||
# generated correctly. In case of a pointer the valueName is used. This is for example the case with NS0
|
||||
# (ns=0;i=8252)
|
||||
valueName = valueName if prepend[0] == '*' else prepend
|
||||
# replace whitespaces between tags and remove newlines
|
||||
return prepend + " = UA_BYTESTRING_NULL;" if not node.value else generateByteStringCode(
|
||||
node.value, valueName, global_var_code, isPointer=asIndirect)
|
||||
|
@ -241,12 +241,26 @@ class Value(object):
|
||||
return extobj
|
||||
|
||||
extobj.value = []
|
||||
members = enc.members
|
||||
|
||||
# The EncodingMask must be skipped.
|
||||
if ebodypart.localName == "EncodingMask":
|
||||
ebodypart = getNextElementNode(ebodypart)
|
||||
|
||||
for e in enc.members:
|
||||
# The SwitchField must be checked.
|
||||
if ebodypart.localName == "SwitchField":
|
||||
# The switch field is the index of the available union fields starting with 1
|
||||
data = int(ebodypart.firstChild.data)
|
||||
if data == 0:
|
||||
# If the switch field is 0 then no field is present. A Union with no fields present has the same meaning as a NULL value.
|
||||
members = []
|
||||
else:
|
||||
members = []
|
||||
members.append(enc.members[data-1])
|
||||
ebodypart = getNextElementNode(ebodypart)
|
||||
|
||||
|
||||
for e in members:
|
||||
# ebodypart can be None if the field is not set, although the field is not optional.
|
||||
if ebodypart is None:
|
||||
if not e.is_optional:
|
||||
@ -326,7 +340,7 @@ class Value(object):
|
||||
else:
|
||||
members = []
|
||||
members.append(enc.members[data-1])
|
||||
ebodypart = getNextElementNode(body)
|
||||
ebodypart = getNextElementNode(body)
|
||||
else:
|
||||
logger.error(str(parent.id) + ": Could not parse <SwitchFiled> for Union.")
|
||||
return self
|
||||
|
Loading…
Reference in New Issue
Block a user