Coverage Report

Created: 2026-11-12 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/src/server/ua_subscription_event.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
 *
5
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
6
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
7
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
8
 *    Copyright 2022, 2025 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
9
 */
10
11
#include <open62541/types.h>
12
#include "ua_server_internal.h"
13
#include "ua_subscription.h"
14
15
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
16
17
static UA_StatusCode
18
readSAOfromEventInstance(UA_FilterEvalContext *ctx,
19
                         const UA_SimpleAttributeOperand *sao,
20
0
                         UA_Variant *value) {
21
    /* EventInstance in the information model defined? */
22
0
    const UA_NodeId *ei = ctx->ed.eventInstance;
23
0
    if(!ei)
24
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
25
26
    /* Prepare the ReadValueId */
27
0
    UA_ReadValueId rvi;
28
0
    UA_ReadValueId_init(&rvi);
29
0
    rvi.indexRange = sao->indexRange;
30
0
    rvi.attributeId = sao->attributeId;
31
32
    /* Read the value */
33
0
    UA_DataValue v;
34
0
    if(sao->browsePathSize == 0) {
35
        /* If this list (browsePath) is empty, the Node is the instance of the
36
         * TypeDefinition. (Part 4, 7.4.4.5) */
37
0
        rvi.nodeId = *ei;
38
39
        /* A Condition is an indirection. Look up the target node. */
40
        /* TODO: check for Branches! One Condition could have multiple Branches */
41
0
        UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
42
0
        if(UA_NodeId_equal(&sao->typeDefinitionId, &conditionTypeId)) {
43
#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
44
            UA_StatusCode res = UA_getConditionId(ctx->server, ctx->ed.eventInstance, &rvi.nodeId);
45
            UA_CHECK_STATUS(res, return res);
46
#else
47
0
            return UA_STATUSCODE_BADNOTSUPPORTED;
48
0
#endif
49
0
        }
50
51
0
        v = readWithSession(ctx->server, ctx->session, &rvi, UA_TIMESTAMPSTORETURN_NEITHER);
52
0
    } else {
53
        /* Resolve the browse path, starting from the event-source (and not the
54
         * typeDefinitionId). */
55
0
        UA_BrowsePathResult bpr =
56
0
            browseSimplifiedBrowsePath(ctx->server, *ei, sao->browsePathSize, sao->browsePath);
57
0
        if(bpr.targetsSize == 0 && bpr.statusCode == UA_STATUSCODE_GOOD)
58
0
            bpr.statusCode = UA_STATUSCODE_BADNOTFOUND;
59
0
        if(bpr.statusCode != UA_STATUSCODE_GOOD) {
60
0
            UA_StatusCode res = bpr.statusCode;
61
0
            UA_BrowsePathResult_clear(&bpr);
62
0
            return res;
63
0
        }
64
65
        /* Use the first match */
66
0
        rvi.nodeId = bpr.targets[0].targetId.nodeId;
67
0
        v = readWithSession(ctx->server, ctx->session, &rvi, UA_TIMESTAMPSTORETURN_NEITHER);
68
0
        UA_BrowsePathResult_clear(&bpr);
69
0
    }
70
71
    /* Validate the result */
72
0
    if(v.status != UA_STATUSCODE_GOOD) {
73
0
        UA_Variant_clear(&v.value);
74
0
        return v.status;
75
0
    }
76
0
    if(!v.hasValue)
77
0
        return UA_STATUSCODE_BADNODATAAVAILABLE;
78
79
    /* Move the result to the output */
80
0
    *value = v.value;
81
0
    return UA_STATUSCODE_GOOD;
82
0
}
83
84
/***************/
85
/* Filter Eval */
86
/***************/
87
88
/* Names of the mandatory event properties (in the BaseEventType) */
89
#define MANDATORY_EVENT_PROPERTIES_COUNT 8
90
static UA_String mandatoryEventProperties[MANDATORY_EVENT_PROPERTIES_COUNT] = {
91
    UA_STRING_STATIC("/EventId"),
92
    UA_STRING_STATIC("/EventType"),
93
    UA_STRING_STATIC("/SourceNode"),
94
    UA_STRING_STATIC("/SourceName"),
95
    UA_STRING_STATIC("/Time"),
96
    UA_STRING_STATIC("/ReceiveTime"),
97
    UA_STRING_STATIC("/Message"),
98
    UA_STRING_STATIC("/Severity")
99
};
100
101
void
102
0
UA_FilterEvalContext_init(UA_FilterEvalContext *ctx) {
103
0
    memset(ctx, 0, sizeof(UA_FilterEvalContext));
104
0
}
105
106
void
107
0
UA_FilterEvalContext_reset(UA_FilterEvalContext *ctx) {
108
0
    UA_KeyValueMap_clear(&ctx->fieldCache);
109
110
    /* The data of the EventId is either in the eventIdBuf or in the fieldCache
111
     * or in the ed. So no memory to free here. Keep the EventId if it points to
112
     * the random-id bytes for the next evaluation. */
113
0
    if(ctx->eventId.data != ctx->eventIdBuf)
114
0
        UA_ByteString_init(&ctx->eventId);
115
0
}
116
117
UA_StatusCode
118
0
cacheEventId(UA_FilterEvalContext *ctx) {
119
    /* Already cached */
120
0
    if(ctx->eventId.length > 0)
121
0
        return UA_STATUSCODE_GOOD;
122
123
    /* Resolve from the Key-Value Map - This does not make a deep copy */
124
0
    const UA_EventDescription *ed = &ctx->ed;
125
0
    if(ed && ed->eventFields) {
126
0
        const UA_Variant *found =
127
0
            UA_KeyValueMap_get(ed->eventFields, UA_QUALIFIEDNAME(0, "/EventId"));
128
0
        if(found) {
129
0
            if(!UA_Variant_hasScalarType(found, &UA_TYPES[UA_TYPES_BYTESTRING]))
130
0
                return UA_STATUSCODE_BADTYPEMISMATCH;
131
0
            ctx->eventId = *(UA_ByteString*)found->data; /* shallow copy */
132
0
            return UA_STATUSCODE_GOOD;
133
0
        }
134
0
    }
135
136
    /* Resolve from the EventInstance. But only if a useful identifier
137
     * (ByteString, length > 0) has been set in the information model. */
138
0
    static UA_QualifiedName eventIdName = {0, UA_STRING_STATIC("EventId")};
139
0
    UA_SimpleAttributeOperand sao;
140
0
    UA_SimpleAttributeOperand_init(&sao);
141
0
    sao.attributeId = UA_ATTRIBUTEID_VALUE;
142
0
    sao.browsePath = &eventIdName;
143
0
    sao.browsePathSize = 1;
144
145
0
    UA_Variant val;
146
0
    UA_Variant_init(&val);
147
0
    UA_StatusCode res = readSAOfromEventInstance(ctx, &sao, &val);
148
0
    if(res == UA_STATUSCODE_GOOD) {
149
0
        UA_Boolean isIdString = UA_Variant_hasScalarType(&val, &UA_TYPES[UA_TYPES_BYTESTRING]);
150
0
        UA_assert(!isIdString || val.data != NULL); /* pacify a clang-analyzer warning */
151
0
        if(isIdString && ((UA_ByteString*)val.data)->length > 0) {
152
0
            res = UA_KeyValueMap_set(&ctx->fieldCache,
153
0
                                     UA_QUALIFIEDNAME(0, "/EventId"), &val);
154
0
            UA_Variant_clear(&val);
155
0
            if(res != UA_STATUSCODE_GOOD)
156
0
                return res;
157
0
            const UA_Variant *cached =
158
0
                UA_KeyValueMap_get(&ctx->fieldCache,
159
0
                                   UA_QUALIFIEDNAME(0, "/EventId"));
160
0
            ctx->eventId = *(UA_ByteString*)cached->data; /* shallow copy */
161
0
            return UA_STATUSCODE_GOOD;
162
0
        }
163
164
        /* Continue to create a random ByteString */
165
0
        UA_Variant_clear(&val);
166
0
    }
167
168
    /* If nothing is explicitly defined, create a random 16-byte ByteString */
169
0
    UA_UInt32 *ids = (UA_UInt32*)ctx->eventIdBuf;
170
0
    ids[0] = UA_UInt32_random();
171
0
    ids[1] = UA_UInt32_random();
172
0
    ids[2] = UA_UInt32_random();
173
0
    ids[3] = UA_UInt32_random();
174
0
    ctx->eventId = (UA_ByteString){16, ctx->eventIdBuf};
175
0
    return UA_STATUSCODE_GOOD;
176
0
}
177
178
/* The SAO string is not always in the "normal form" that is the output of
179
 * UA_SimpleAttributeOperand_print. For example, we can have an implicit #Value
180
 * postfix or the path-browsenames prefixed with 0: for ns0. Also, for the
181
 * map-keys as QualifiedNames, we use the key-nsindex as the default nsindex for
182
 * the path.
183
 *
184
 * In order to compare with a non-normal-form SAO string, we decode and compare
185
 * the SAO directly. This is slower, so we try the normal form string-compare
186
 * first. */
187
static UA_Variant *
188
getEventFieldNonNormalForm(UA_Server *server, const UA_KeyValueMap *eventFields,
189
0
                           const UA_SimpleAttributeOperand *sao) {
190
0
    if(!eventFields)
191
0
        return NULL;
192
193
0
    UA_SimpleAttributeOperand keySao;
194
0
    for(size_t i = 0; i < eventFields->mapSize; i++) {
195
0
        UA_KeyValuePair *kvp = &eventFields->map[i];
196
0
        UA_StatusCode res =
197
0
            sao_parseWithDefaultNsIdx(&keySao, kvp->key.name,
198
0
                                      kvp->key.namespaceIndex);
199
0
        if(res != UA_STATUSCODE_GOOD)
200
0
            continue;
201
0
        UA_Boolean found = UA_SimpleAttributeOperand_equal(sao, &keySao);
202
0
        UA_SimpleAttributeOperand_clear(&keySao);
203
0
        if(found)
204
0
            return &kvp->value;
205
0
    }
206
0
    return NULL;
207
0
}
208
209
/* Can return an in-situ value. Check for UA_VARIANT_DATA_NODELETE. */
210
UA_StatusCode
211
resolveSAO(UA_FilterEvalContext *ctx, const UA_SimpleAttributeOperand *sao,
212
0
           UA_Variant *out) {
213
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
214
0
    const UA_EventDescription *ed = &ctx->ed;
215
0
    const UA_Variant *found;
216
0
    UA_Byte pathBuf[512];
217
0
    UA_QualifiedName pathString = {0, {512, pathBuf}};
218
0
    static UA_NodeId baseEventTypeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEEVENTTYPE}};
219
220
    /* Copy into a mutable SAO */
221
0
    UA_SimpleAttributeOperand tmp_sao = *sao;
222
223
    /* Do the lookup without the index-range.
224
     * The index-range from the original sao is used later. */
225
0
    tmp_sao.indexRange = UA_STRING_NULL;
226
227
    /* Initially use the BaseEventTypeId if not defined explicitly.
228
     * If this does not resolve, we try again with i=0 (goto search again). */
229
0
    if(UA_NodeId_isNull(&tmp_sao.typeDefinitionId))
230
0
        tmp_sao.typeDefinitionId = baseEventTypeId;
231
232
0
 search_again:
233
0
    res = UA_SimpleAttributeOperand_print(&tmp_sao, &pathString.name);
234
0
    if(res != UA_STATUSCODE_GOOD)
235
0
        return res;
236
237
    /* Special Case: EventId (generated only once per Event, ignores the IndexRange) */
238
0
    if(UA_String_equal(&pathString.name, &mandatoryEventProperties[0])) {
239
0
        res = cacheEventId(ctx);
240
0
        if(res != UA_STATUSCODE_GOOD)
241
0
            return res;
242
0
        UA_Variant_setScalar(out, &ctx->eventId, &UA_TYPES[UA_TYPES_BYTESTRING]);
243
0
        out->storageType = UA_VARIANT_DATA_NODELETE;
244
0
        return UA_STATUSCODE_GOOD;
245
0
    }
246
247
    /* Source 1: Use the SAO-string to look up from the user-defined key-value
248
     * map (and from the cache) */
249
0
    found = UA_KeyValueMap_get(ed->eventFields, pathString);
250
0
    if(!found)
251
0
        found = UA_KeyValueMap_get(&ctx->fieldCache, pathString);
252
0
    if(!found)
253
0
        found = getEventFieldNonNormalForm(ctx->server, ed->eventFields, &tmp_sao);
254
0
    if(found) {
255
0
        if(sao->indexRange.length == 0) {
256
0
            *out = *found;
257
0
            out->storageType = UA_VARIANT_DATA_NODELETE;
258
0
        } else {
259
0
            UA_NumericRange range;
260
0
            res = UA_NumericRange_parse(&range, sao->indexRange);
261
0
            if(res != UA_STATUSCODE_GOOD)
262
0
               return res;
263
0
            res = UA_Variant_copyRange(found, out, range);
264
0
            UA_free(range.dimensions);
265
0
        }
266
0
        return res;
267
0
    }
268
269
    /* Not found. Print the SAO again with BaseEventTypeId as the
270
     * TypeDefinitionId and try again. This removes any TypeDefinitionId prefix
271
     * from the printed SAO-string. */
272
0
    if(!UA_NodeId_equal(&tmp_sao.typeDefinitionId, &baseEventTypeId)) {
273
0
        tmp_sao.typeDefinitionId = baseEventTypeId;
274
0
        goto search_again;
275
0
    }
276
277
    /* Source 2: Read from the information model */
278
0
    res = readSAOfromEventInstance(ctx, sao, out);
279
0
    if(res == UA_STATUSCODE_GOOD)
280
0
        return UA_STATUSCODE_GOOD;
281
282
    /* Source 3: Use a default for the mandatory fields of the BaseEventType.
283
     * Here we ignore the IndexRange. */
284
0
    UA_String_init(&tmp_sao.indexRange); /* No index range allowed */
285
0
    if(UA_String_equal(&pathString.name, &mandatoryEventProperties[1])) {
286
        /* EventType */
287
0
        return UA_Variant_setScalarCopy(out, &ed->eventType, &UA_TYPES[UA_TYPES_NODEID]);
288
0
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[2])) {
289
        /* SourceNode */
290
0
        return UA_Variant_setScalarCopy(out, &ed->sourceNode, &UA_TYPES[UA_TYPES_NODEID]);
291
0
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[3])) {
292
        /* SourceName. Read the DisplayName from the information model. This
293
         * uses the locale of the session. */
294
0
        UA_ReadValueId rvi;
295
0
        UA_ReadValueId_init(&rvi);
296
0
        rvi.nodeId = ed->sourceNode;
297
0
        rvi.attributeId = UA_ATTRIBUTEID_DISPLAYNAME;
298
0
        UA_DataValue dv = readWithSession(ctx->server, ctx->session, &rvi,
299
0
                                          UA_TIMESTAMPSTORETURN_NEITHER);
300
0
        if(dv.status != UA_STATUSCODE_GOOD) {
301
0
            res = dv.status;
302
0
            UA_DataValue_clear(&dv);
303
0
            return res;
304
0
        }
305
0
        if(dv.value.type != &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) {
306
0
            UA_DataValue_clear(&dv);
307
0
            return UA_STATUSCODE_BADINTERNALERROR;
308
0
        }
309
0
        UA_LocalizedText *displayName = (UA_LocalizedText*)dv.value.data;
310
0
        res = UA_Variant_setScalarCopy(out, &displayName->text, &UA_TYPES[UA_TYPES_STRING]);
311
0
        UA_DataValue_clear(&dv);
312
0
        return res;
313
0
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[4]) ||
314
0
              UA_String_equal(&pathString.name, &mandatoryEventProperties[5])) {
315
        /* Time / ReceiveTime */
316
0
        UA_EventLoop *el = ctx->server->config.eventLoop;
317
0
        UA_DateTime rcvTime = el->dateTime_now(el);
318
0
        return UA_Variant_setScalarCopy(out, &rcvTime, &UA_TYPES[UA_TYPES_DATETIME]);
319
0
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[6])) {
320
        /* Message */
321
0
        return UA_Variant_setScalarCopy(out, &ed->message, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
322
0
    } else if(UA_String_equal(&pathString.name, &mandatoryEventProperties[7])) {
323
        /* Severity */
324
0
        return UA_Variant_setScalarCopy(out, &ed->severity, &UA_TYPES[UA_TYPES_UINT16]);
325
0
    }
326
327
    /* Not found, return an empty Variant */
328
0
    return UA_STATUSCODE_GOOD;
329
0
}
330
331
/***************************/
332
/* Where-Clause Evaluation */
333
/***************************/
334
335
/* Ternary Logic
336
 * -------------
337
 * Similar to SQL, OPC UA Queries use the K3 - Strong Kleene Logic that
338
 * considers ternary values true/false/null (unknown). Every operator result
339
 * (Variant) can be cast to a ternary truth value. See the v2t method below.
340
 * We cast all operands to a ternary truth value before a logical operator is
341
 * applied. */
342
343
typedef enum {
344
    UA_TERNARY_FALSE = -1,
345
    UA_TERNARY_NULL = 0,
346
    UA_TERNARY_TRUE = 1
347
} UA_Ternary;
348
349
static UA_Ternary
350
0
UA_Ternary_and(UA_Ternary first, UA_Ternary second) {
351
0
    if(first == UA_TERNARY_FALSE || second == UA_TERNARY_FALSE)
352
0
        return UA_TERNARY_FALSE;
353
0
    if(first == UA_TERNARY_NULL || second == UA_TERNARY_NULL)
354
0
        return UA_TERNARY_NULL;
355
0
    return UA_TERNARY_TRUE;
356
0
}
357
358
static UA_Ternary
359
0
UA_Ternary_or(UA_Ternary first, UA_Ternary second) {
360
0
    if(first == UA_TERNARY_TRUE || second == UA_TERNARY_TRUE)
361
0
        return UA_TERNARY_TRUE;
362
0
    if(first == UA_TERNARY_NULL || second == UA_TERNARY_NULL)
363
0
        return UA_TERNARY_NULL;
364
0
    return UA_TERNARY_FALSE;
365
0
}
366
367
/* Part 4: The NOT operator always evaluates to NULL if applied to a NULL
368
 * operand. We simply swap true/false. */
369
static UA_Ternary
370
0
UA_Ternary_not(UA_Ternary v) {
371
0
    return (UA_Ternary)((int)v * -1);
372
0
}
373
374
static const UA_Boolean bFalse = false;
375
static const UA_Boolean bTrue  = true;
376
377
0
static UA_Variant t2v(UA_Ternary t) {
378
0
    UA_Variant v;
379
0
    UA_Variant_init(&v);
380
0
    switch(t) {
381
0
    case UA_TERNARY_FALSE:
382
0
        UA_Variant_setScalar(&v, (void*)(uintptr_t)&bFalse, &UA_TYPES[UA_TYPES_BOOLEAN]);
383
0
        break;
384
0
    case UA_TERNARY_TRUE:
385
0
        UA_Variant_setScalar(&v, (void*)(uintptr_t)&bTrue, &UA_TYPES[UA_TYPES_BOOLEAN]);
386
0
        break;
387
0
    default:
388
0
        return v;
389
0
    }
390
0
    v.storageType = UA_VARIANT_DATA_NODELETE;
391
0
    return v;
392
0
}
393
394
/* Forward declarations */
395
static void
396
castNumerical(const UA_Variant *in, const UA_DataType *type, UA_Variant *out);
397
static UA_StatusCode
398
castImplicitFromString(const UA_Variant *in, const UA_DataType *outType, UA_Variant *out);
399
400
/* For translating to a ternary truth-value we apply the rules for the "explicit
401
 * casting" to a Boolean. Because implicit casting from numerical to Boolean is
402
 * not possible as per Table 125 in the standard. */
403
0
static UA_Ternary v2t(const UA_Variant *v) {
404
    /* Empty -> NULL, Arrays are undefined in the standard */
405
0
    if(UA_Variant_isEmpty(v) || !UA_Variant_isScalar(v))
406
0
        return UA_TERNARY_NULL;
407
408
    /* Try to cast to Boolean. The variant remains empty if this fails.
409
     * Otherwise the bTrue/bFalse singletons are set. */
410
0
    UA_Variant vBool;
411
0
    UA_Variant_init(&vBool);
412
0
    if(v->type != &UA_TYPES[UA_TYPES_STRING])
413
0
        castNumerical(v, &UA_TYPES[UA_TYPES_BOOLEAN], &vBool);
414
0
    else
415
0
        castImplicitFromString(v, &UA_TYPES[UA_TYPES_BOOLEAN], &vBool);
416
417
0
    if(!vBool.type)
418
0
        return UA_TERNARY_NULL;
419
0
    return (vBool.data == &bTrue) ? UA_TERNARY_TRUE : UA_TERNARY_FALSE;
420
0
}
421
422
/* Type Casting Rules
423
 * ------------------
424
 * For comparison operations values from different datatypes can be implicitly
425
 * or explicitly cast. The standard defines rules to selected the target type
426
 * for casting and when implicit casts are possible. */
427
428
/* Defined in Part 4 Table 123 "Data Precedence Rules". Implicit casting is
429
 * always to the type of lower precedence value. */
430
static UA_Byte typePrecedence[UA_DATATYPEKINDS] = {
431
    12, 10, 11, 8, 9, 5, 6, 3, 4, 2, 1, 14, 255, 13, 255, 255, 16,
432
    15, 7, 18, 17, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
433
};
434
435
/* Type conversion table from the standard.
436
 * 0 -> Same Type, 1 -> Implicit Cast, 2 -> Only explicit Cast, -1 -> cast invalid */
437
static UA_SByte convertLookup[21][21] = {
438
    { 0, 1,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 1,-1, 2,-1,-1, 1, 1, 1,-1},
439
    { 2, 0,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 1,-1, 2,-1,-1, 1, 1, 1,-1},
440
    {-1,-1, 0,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
441
    {-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1},
442
    { 2, 2,-1,-1, 0,-1, 2,-1, 2, 2, 2,-1, 2,-1, 2,-1,-1, 2, 2, 2,-1},
443
    {-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1, 2,-1,-1, 1,-1,-1,-1,-1,-1,-1},
444
    { 2, 2,-1,-1, 1,-1, 0,-1, 2, 2, 2,-1, 2,-1, 2,-1,-1, 2, 2, 2,-1},
445
    {-1,-1, 2,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1},
446
    { 2, 2,-1,-1, 1,-1, 1,-1, 0, 1, 1,-1, 2,-1, 2,-1,-1, 2, 1, 1,-1},
447
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 0, 1,-1, 2, 2, 2,-1,-1, 2, 2, 1,-1},
448
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 2, 0,-1, 2, 2, 2,-1,-1, 2, 2, 2,-1},
449
    {-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1, 0,-1,-1, 1,-1,-1,-1,-1,-1,-1},
450
    { 2, 2,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 0,-1, 2,-1,-1, 1, 1, 1,-1},
451
    {-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1,-1,-1, 0,-1,-1,-1, 2, 1, 1,-1},
452
    { 1, 1,-1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,-1, 0, 2, 2, 1, 1, 1,-1},
453
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 0,-1,-1,-1,-1,-1},
454
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 0,-1,-1,-1,-1},
455
    { 2, 2,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 2, 1, 2,-1,-1, 0, 1, 1,-1},
456
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 1, 1,-1, 2, 2, 2,-1,-1, 2, 0, 1,-1},
457
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 2, 1,-1, 2, 2, 2,-1,-1, 2, 2, 0,-1},
458
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0}
459
};
460
461
/* This array maps the index of the DataType-Kind to the index of the type
462
 * conversion matrix (255 -> not contained in the matrix) */
463
static UA_Byte convertLookupIndex[UA_DATATYPEKINDS] = {
464
    0,  12,  1,  8, 17,  9, 18, 10, 19,  6, 4,  14,  3,  7,  2,
465
    20, 11,  5, 13, 16, 15,255,255,255,255,255,255,255,255,255,255
466
};
467
468
/* Returns the target type for implicit cassting or NULL if no implicit casting
469
 * is possible */
470
static const UA_DataType *
471
0
implicitCastTargetType(const UA_DataType *t1, const UA_DataType *t2) {
472
0
    if(!t1 || !t2)
473
0
        return NULL;
474
0
    if(t1 == t2)
475
0
        return t1;
476
477
    /* Get the type precedence. Return if no implicit casting is possible. */
478
0
    UA_Byte p1 = typePrecedence[t1->typeKind];
479
0
    UA_Byte p2 = typePrecedence[t2->typeKind];
480
0
    if(p1 == UA_BYTE_MAX || p2 == UA_BYTE_MAX)
481
0
        return NULL;
482
483
    /* Which is the target type based on the precedence rules? */
484
0
    const UA_DataType *targetType = (p1 < p2) ? t1 : t2;
485
0
    const UA_DataType *sourceType = (p1 < p2) ? t2 : t1;
486
487
    /* Lookup the casting rule */
488
0
    UA_Byte sourceIndex = convertLookupIndex[sourceType->typeKind];
489
0
    UA_Byte targetIndex = convertLookupIndex[targetType->typeKind];
490
0
    if(sourceIndex == UA_BYTE_MAX || targetIndex == UA_BYTE_MAX)
491
0
        return NULL;
492
0
    UA_SByte castingRule = convertLookup[sourceIndex][targetIndex];
493
494
    /* Is implicit casting allowed? */
495
0
    if(castingRule != 0 && castingRule != 1)
496
0
        return NULL;
497
0
    return targetType;
498
0
}
499
500
/* Cast Numerical
501
 * --------------
502
 * To reduce the number of cases we first "normalize" to either of
503
 * Int64/UInt64/Double. Then cast from there to the target type. This works for
504
 * all numericals (not only the implicit conversion).
505
 *
506
 * Numerical conversion rules from the standard:
507
 *
508
 * - If the conversion fails the result is a null value.
509
 * - Floating point values are rounded by adding 0.5 and truncating when they
510
 *   are converted to integer values.
511
 * - Converting a value that is outside the range of the target type causes a
512
 *   conversion error. */
513
514
#define UA_CAST_SIGNED(t, T)                                           \
515
0
    if(i < (UA_Int64)T##_MIN || i > (UA_Int64)T##_MAX) {               \
516
0
        UA_free(data);                                                 \
517
0
        return;                                                        \
518
0
    }                                                                  \
519
0
    *(t*)data = (t)i;                                                  \
520
0
    do { } while(0)
521
522
#define UA_CAST_UNSIGNED(t, T)                                         \
523
0
    if(u > T##_MAX) {                                                  \
524
0
        UA_free(data);                                                 \
525
0
        return;                                                        \
526
0
    }                                                                  \
527
0
    *(t*)data = (t)u;                                                  \
528
0
    do { } while(0)
529
530
#define UA_CAST_FLOAT(t, T)                                            \
531
0
    if(f + 0.5 < (UA_Double)T##_MIN || f + 0.5 > (UA_Double)T##_MAX) { \
532
0
        UA_free(data);                                                 \
533
0
        return;                                                        \
534
0
    }                                                                  \
535
0
    *(t*)data = (t)(f + 0.5);                                          \
536
0
    do { } while(0)
537
538
/* We can cast between any numerical type. So this can be reused for explicit casting. */
539
static void
540
0
castNumerical(const UA_Variant *in, const UA_DataType *type, UA_Variant *out) {
541
0
    UA_assert(UA_Variant_isScalar(in));
542
0
    UA_assert(UA_Variant_isEmpty(out));
543
544
0
    UA_Int64  i = 0;
545
0
    UA_UInt64 u = 0;
546
0
    UA_Double f = 0.0;
547
548
0
    const UA_DataTypeKind ink = (UA_DataTypeKind)in->type->typeKind;
549
0
    switch(ink) {
550
0
    case UA_DATATYPEKIND_SBYTE:  i = *(UA_SByte*)in->data; break;
551
0
    case UA_DATATYPEKIND_INT16:  i = *(UA_Int16*)in->data; break;
552
0
    case UA_DATATYPEKIND_INT32:  i = *(UA_Int32*)in->data; break;
553
0
    case UA_DATATYPEKIND_INT64:  i = *(UA_Int64*)in->data; break;
554
0
    case UA_DATATYPEKIND_BYTE: /* or */
555
0
    case UA_DATATYPEKIND_BOOLEAN: u = *(UA_Byte*)in->data; break;
556
0
    case UA_DATATYPEKIND_UINT16:  u = *(UA_UInt16*)in->data; break;
557
0
    case UA_DATATYPEKIND_UINT32: /* or */
558
0
    case UA_DATATYPEKIND_STATUSCODE: u = *(UA_UInt32*)in->data; break;
559
0
    case UA_DATATYPEKIND_UINT64: u = *(UA_UInt64*)in->data; break;
560
0
    case UA_DATATYPEKIND_FLOAT:  f = *(UA_Float*)in->data; break;
561
0
    case UA_DATATYPEKIND_DOUBLE: f = *(UA_Double*)in->data; break;
562
0
    default: return;
563
0
    }
564
565
    /* Boolean is true if the numerical input is nonzero */
566
0
    if(type == &UA_TYPES[UA_TYPES_BOOLEAN]) {
567
0
        const UA_Boolean *b = &bFalse;
568
0
        if(i != 0 || u != 0 || f != 0.0)
569
0
            b = &bTrue;
570
0
        UA_Variant_setScalar(out, (void*)(uintptr_t)b, type);
571
0
        out->storageType = UA_VARIANT_DATA_NODELETE;
572
0
        return;
573
0
    }
574
575
    /* Allocate the output data. Return NULL value if malloc fails. */
576
0
    void *data = UA_new(type);
577
0
    if(!data)
578
0
        return;
579
580
0
    if(ink == UA_DATATYPEKIND_SBYTE || ink == UA_DATATYPEKIND_INT16 ||
581
0
       ink == UA_DATATYPEKIND_INT32 || ink == UA_DATATYPEKIND_INT64) {
582
        /* Cast from signed */
583
0
        switch(type->typeKind) {
584
0
        case UA_DATATYPEKIND_SBYTE:  UA_CAST_SIGNED(UA_SByte, UA_SBYTE); break;
585
0
        case UA_DATATYPEKIND_INT16:  UA_CAST_SIGNED(UA_Int16, UA_INT16); break;
586
0
        case UA_DATATYPEKIND_INT32:  UA_CAST_SIGNED(UA_Int32, UA_INT32); break;
587
0
        case UA_DATATYPEKIND_INT64:  *(UA_Int64*)data = i; break;
588
0
        case UA_DATATYPEKIND_BYTE:   UA_CAST_SIGNED(UA_Byte, UA_BYTE); break;
589
0
        case UA_DATATYPEKIND_UINT16: UA_CAST_SIGNED(UA_UInt16, UA_UINT16); break;
590
0
        case UA_DATATYPEKIND_UINT32: UA_CAST_SIGNED(UA_UInt32, UA_UINT32); break;
591
0
        case UA_DATATYPEKIND_UINT64: UA_CAST_SIGNED(UA_UInt64, UA_UINT64); break;
592
0
        case UA_DATATYPEKIND_FLOAT:  *(UA_Float*)data = (UA_Float)i; break;
593
0
        case UA_DATATYPEKIND_DOUBLE: *(UA_Double*)data = (UA_Double)i; break;
594
0
        default:
595
0
            UA_free(data);
596
0
            return;
597
0
        }
598
0
    } else if(ink == UA_DATATYPEKIND_BOOLEAN || ink == UA_DATATYPEKIND_STATUSCODE ||
599
0
              ink == UA_DATATYPEKIND_BYTE || ink == UA_DATATYPEKIND_UINT16 ||
600
0
              ink == UA_DATATYPEKIND_UINT32 || ink == UA_DATATYPEKIND_UINT64) {
601
        /* Cast from unsigned */
602
0
        switch(type->typeKind) {
603
0
        case UA_DATATYPEKIND_SBYTE:  UA_CAST_UNSIGNED(UA_SByte, UA_SBYTE); break;
604
0
        case UA_DATATYPEKIND_INT16:  UA_CAST_UNSIGNED(UA_Int16, UA_INT16); break;
605
0
        case UA_DATATYPEKIND_INT32:  UA_CAST_UNSIGNED(UA_Int32, UA_INT32); break;
606
0
        case UA_DATATYPEKIND_INT64:  UA_CAST_UNSIGNED(UA_Int64, UA_INT64); break;
607
0
        case UA_DATATYPEKIND_BYTE:   UA_CAST_UNSIGNED(UA_Byte, UA_BYTE); break;
608
0
        case UA_DATATYPEKIND_UINT16: UA_CAST_UNSIGNED(UA_UInt16, UA_UINT16); break;
609
0
        case UA_DATATYPEKIND_UINT32: UA_CAST_UNSIGNED(UA_UInt32, UA_UINT32); break;
610
0
        case UA_DATATYPEKIND_UINT64: *(UA_UInt64*)data = u; break;
611
0
        case UA_DATATYPEKIND_FLOAT:  *(UA_Float*)data = (UA_Float)u; break;
612
0
        case UA_DATATYPEKIND_DOUBLE: *(UA_Double*)data = (UA_Double)u; break;
613
0
        default:
614
0
            UA_free(data);
615
0
            return;
616
0
        }
617
0
    } else {
618
        /* Cast from float */
619
0
        if(f != f) {
620
            /* NaN cannot be cast */
621
0
            UA_free(data);
622
0
            return;
623
0
        }
624
0
        switch(type->typeKind) {
625
0
        case UA_DATATYPEKIND_SBYTE:  UA_CAST_FLOAT(UA_SByte, UA_SBYTE); break;
626
0
        case UA_DATATYPEKIND_INT16:  UA_CAST_FLOAT(UA_Int16, UA_INT16); break;
627
0
        case UA_DATATYPEKIND_INT32:  UA_CAST_FLOAT(UA_Int32, UA_INT32); break;
628
0
        case UA_DATATYPEKIND_INT64:  UA_CAST_FLOAT(UA_Int64, UA_INT64); break;
629
0
        case UA_DATATYPEKIND_BYTE:   UA_CAST_FLOAT(UA_Byte, UA_BYTE); break;
630
0
        case UA_DATATYPEKIND_UINT16: UA_CAST_FLOAT(UA_UInt16, UA_UINT16); break;
631
0
        case UA_DATATYPEKIND_UINT32: UA_CAST_FLOAT(UA_UInt32, UA_UINT32); break;
632
0
        case UA_DATATYPEKIND_UINT64: UA_CAST_FLOAT(UA_UInt64, UA_UINT64); break;
633
0
        case UA_DATATYPEKIND_FLOAT:  *(UA_Float*)data = (UA_Float)f; break;
634
0
        case UA_DATATYPEKIND_DOUBLE: *(UA_Double*)data = (UA_Double)f; break;
635
0
        default:
636
0
            UA_free(data);
637
0
            return;
638
0
        }
639
0
    }
640
641
0
    UA_Variant_setScalar(out, data, type);
642
0
}
643
644
/* Implicit Casting
645
 * ---------------- */
646
647
0
static UA_INLINE UA_Byte uppercase(UA_Byte in) { return in & (UA_Byte)~32; }
648
649
static UA_StatusCode
650
0
castImplicitFromString(const UA_Variant *in, const UA_DataType *outType, UA_Variant *out) {
651
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
652
653
0
    if(outType == &UA_TYPES[UA_TYPES_BOOLEAN]) {
654
        /* String -> Boolean
655
         *
656
         * Part 4 says: String values containing "true", "false", "1" or "0"
657
         * can be converted to Boolean values. Other string values cause a
658
         * conversion error. In this case Strings are case-insensitive. */
659
0
        const UA_Boolean *b;
660
0
        const UA_String *inStr = (const UA_String*)in->data;
661
0
        if(inStr->length == 1 && inStr->data[0] == '0') {
662
0
            b = &bFalse;
663
0
        } else if(inStr->length == 1 && inStr->data[0] == '1') {
664
0
            b = &bTrue;
665
0
        } else if(inStr->length == 4 &&
666
0
                  uppercase(inStr->data[0])== 'T' && uppercase(inStr->data[1])== 'R' &&
667
0
                  uppercase(inStr->data[2])== 'U' && uppercase(inStr->data[3])== 'E') {
668
0
            b = &bTrue;
669
0
        } else if(inStr->length == 5              && uppercase(inStr->data[0])== 'F' &&
670
0
                  uppercase(inStr->data[1])== 'A' && uppercase(inStr->data[2])== 'L' &&
671
0
                  uppercase(inStr->data[3])== 'S' && uppercase(inStr->data[4])== 'E') {
672
0
            b = &bFalse;
673
0
        } else {
674
0
            return UA_STATUSCODE_BADTYPEMISMATCH;
675
0
        }
676
0
        UA_Variant_setScalar(out, (void*)(uintptr_t)b, outType);
677
0
        out->storageType = UA_VARIANT_DATA_NODELETE;
678
0
        return UA_STATUSCODE_GOOD;
679
0
    } else if(outType == &UA_TYPES[UA_TYPES_GUID]) {
680
        /* String -> Guid */
681
0
        UA_Guid guid;
682
0
        res = UA_Guid_parse(&guid, *(UA_String*)in->data);
683
0
        if(res != UA_STATUSCODE_GOOD)
684
0
            return res;
685
0
        return UA_Variant_setScalarCopy(out, &guid, outType);
686
0
    }
687
688
0
#ifdef UA_ENABLE_JSON_ENCODING
689
    /* String -> Numerical, uses the JSON decoding */
690
0
    else if(UA_DataType_isNumeric(outType)) {
691
0
        void *outData = UA_new(outType);
692
0
        if(!outData)
693
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
694
0
        res = UA_decodeJson((const UA_ByteString*)in->data, outData, outType, NULL);
695
0
        if(res != UA_STATUSCODE_GOOD) {
696
0
            UA_free(outData);
697
0
            return res;
698
0
        }
699
0
        UA_Variant_setScalar(out, outData, outType);
700
0
        return UA_STATUSCODE_GOOD;
701
0
    }
702
0
#endif
703
704
    /* No implicit casting possible */
705
0
    return UA_STATUSCODE_BADTYPEMISMATCH;
706
0
}
707
708
static UA_StatusCode
709
0
castImplicit(const UA_Variant *in, const UA_DataType *outType, UA_Variant *out) {
710
    /* Of the input is empty, casting results in a NULL value */
711
0
    if(UA_Variant_isEmpty(in))
712
0
        return UA_STATUSCODE_GOOD;
713
714
    /* TODO: We only support scalar values for now */
715
0
    if(!UA_Variant_isScalar(in))
716
0
        return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
717
718
    /* No casting necessary */
719
0
    if(in->type == outType) {
720
0
        *out = *in;
721
0
        out->storageType = UA_VARIANT_DATA_NODELETE;
722
0
        return UA_STATUSCODE_GOOD;
723
0
    }
724
725
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
726
0
    switch(in->type->typeKind) {
727
0
    case UA_DATATYPEKIND_EXPANDEDNODEID: {
728
        /* ExpandedNodeId -> String */
729
0
        if(outType != &UA_TYPES[UA_TYPES_STRING])
730
0
            break;
731
0
        UA_String *outStr = UA_String_new();
732
0
        if(!outStr)
733
0
            return UA_STATUSCODE_BADOUTOFMEMORY;
734
0
        res = UA_ExpandedNodeId_print((const UA_ExpandedNodeId*)in->data, outStr);
735
0
        if(res != UA_STATUSCODE_GOOD) {
736
0
            UA_free(outStr);
737
0
            break;
738
0
        }
739
0
        UA_Variant_setScalar(out, outStr, outType);
740
0
        break;
741
0
    }
742
743
0
    case UA_DATATYPEKIND_NODEID: {
744
0
        if(outType == &UA_TYPES[UA_TYPES_STRING]) {
745
            /* NodeId -> String */
746
0
            UA_String *outStr = UA_String_new();
747
0
            if(!outStr)
748
0
                return UA_STATUSCODE_BADOUTOFMEMORY;
749
0
            res = UA_NodeId_print((const UA_NodeId*)in->data, outStr);
750
0
            if(res != UA_STATUSCODE_GOOD) {
751
0
                UA_free(outStr);
752
0
                break;
753
0
            }
754
0
            UA_Variant_setScalar(out, outStr, outType);
755
0
        } else if(outType == &UA_TYPES[UA_TYPES_EXPANDEDNODEID]) {
756
            /* NodeId -> ExpandedNodeId */
757
0
            UA_ExpandedNodeId *eid = UA_ExpandedNodeId_new();
758
0
            if(!eid)
759
0
                return UA_STATUSCODE_BADOUTOFMEMORY;
760
0
            res = UA_NodeId_copy((const UA_NodeId*)in->data, &eid->nodeId);
761
0
            if(res != UA_STATUSCODE_GOOD) {
762
0
                UA_free(eid);
763
0
                break;
764
0
            }
765
0
            UA_Variant_setScalar(out, eid, outType);
766
0
        }
767
0
        break;
768
0
    }
769
770
0
    case UA_DATATYPEKIND_STRING:
771
0
        res = castImplicitFromString(in, outType, out);
772
0
        break;
773
774
0
    case UA_DATATYPEKIND_LOCALIZEDTEXT: {
775
0
        if(outType != &UA_TYPES[UA_TYPES_STRING])
776
0
            break;
777
        /* LocalizedText -> String */
778
0
        UA_LocalizedText *inLT = (UA_LocalizedText*)in->data;
779
0
        res = UA_Variant_setScalarCopy(out, &inLT->text, outType);
780
0
        break;
781
0
    }
782
783
0
    case UA_DATATYPEKIND_QUALIFIEDNAME: {
784
0
        UA_QualifiedName *inQN = (UA_QualifiedName*)in->data;
785
0
        if(outType == &UA_TYPES[UA_TYPES_STRING]) {
786
            /* QualifiedName -> String */
787
0
            res = UA_Variant_setScalarCopy(out, &inQN->name, outType);
788
0
        } else if(outType == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) {
789
            /* QualifiedName -> LocalizedText */
790
0
            UA_LocalizedText lt;
791
0
            lt.text = inQN->name;
792
0
            lt.locale = UA_STRING_NULL;
793
0
            res = UA_Variant_setScalarCopy(out, &lt, outType);
794
0
        }
795
0
        break;
796
0
    }
797
798
0
    default:
799
        /* Implicit casting from a numerical value to Boolean is not possible.
800
         * Explicit casting is possible and evaluates to true if the value is
801
         * non-null. */
802
0
        if(outType == &UA_TYPES[UA_TYPES_BOOLEAN])
803
0
            return res;
804
805
        /* Try casting between numericals (also works for Boolean and StatusCode
806
         * input). The conversion can fail if the limits of the output type are
807
         * exceeded and then results in a NULL value. */
808
0
        castNumerical(in, outType, out);
809
0
    }
810
811
0
    return res;
812
0
}
813
814
/* Filter Evaluation
815
 * ----------------- */
816
817
/* Initialize every pushed operand so cleanup is safe even if resolution fails. */
818
static UA_Variant *
819
0
pushOperand(UA_FilterEvalContext *ctx) {
820
0
    UA_Variant *v = &ctx->operandStack[ctx->top++];
821
0
    UA_Variant_init(v);
822
0
    return v;
823
0
}
824
825
static UA_StatusCode
826
0
resolveOperand(UA_FilterEvalContext *ctx, UA_ExtensionObject *op, UA_Variant *out) {
827
0
    if(op->encoding != UA_EXTENSIONOBJECT_DECODED &&
828
0
       op->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE)
829
0
        return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
830
831
    /* Result of an operator that was evaluated prior */
832
0
    if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) {
833
0
        UA_ElementOperand *eo = (UA_ElementOperand*)op->content.decoded.data;
834
0
        *out = ctx->operatorResults[eo->index];
835
0
        out->storageType = UA_VARIANT_DATA_NODELETE;
836
0
        return UA_STATUSCODE_GOOD;
837
0
    }
838
839
    /* Literal value */
840
0
    if(op->content.decoded.type == &UA_TYPES[UA_TYPES_LITERALOPERAND]) {
841
0
        UA_LiteralOperand *lo = (UA_LiteralOperand*)op->content.decoded.data;
842
0
        *out = lo->value;
843
0
        out->storageType = UA_VARIANT_DATA_NODELETE;
844
0
        return UA_STATUSCODE_GOOD;
845
0
    }
846
847
    /* SimpleAttributeOperand with a BrowsePath */
848
0
    if(op->content.decoded.type == &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]) {
849
0
        UA_SimpleAttributeOperand *sao =
850
0
            (UA_SimpleAttributeOperand*)op->content.decoded.data;
851
0
        return resolveSAO(ctx, sao, out);
852
0
    }
853
854
0
    return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
855
0
}
856
857
static UA_StatusCode
858
0
ofTypeOperator(UA_FilterEvalContext *ctx, size_t index) {
859
0
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
860
0
    UA_assert(elm->filterOperandsSize == 1);
861
862
    /* Get the operand. Must be a literal NodeId */
863
0
    UA_Variant *op0 = pushOperand(ctx);
864
0
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
865
0
    if(res != UA_STATUSCODE_GOOD || !UA_Variant_hasScalarType(op0, &UA_TYPES[UA_TYPES_NODEID]))
866
0
        return UA_STATUSCODE_BADFILTEROPERANDINVALID;
867
0
    const UA_NodeId *operandTypeId = (const UA_NodeId *)op0->data;
868
869
    /* Read the /EventType event field */
870
0
    static UA_QualifiedName eventTypeName = {0, UA_STRING_STATIC("EventType")};
871
0
    UA_SimpleAttributeOperand sao;
872
0
    UA_SimpleAttributeOperand_init(&sao);
873
0
    sao.attributeId = UA_ATTRIBUTEID_VALUE;
874
0
    sao.browsePath = &eventTypeName;
875
0
    sao.browsePathSize = 1;
876
0
    UA_Variant eventType;
877
0
    UA_Variant_init(&eventType);
878
0
    res = resolveSAO(ctx, &sao, &eventType);
879
0
    if(res != UA_STATUSCODE_GOOD)
880
0
        return res;
881
0
    if(!UA_Variant_hasScalarType(&eventType, &UA_TYPES[UA_TYPES_NODEID])) {
882
0
        UA_Variant_clear(&eventType);
883
0
        return UA_STATUSCODE_BADINTERNALERROR;
884
0
    }
885
886
    /* Is the /EventType a subtype of the requested type? */
887
0
    UA_Boolean ofType =
888
0
        isNodeInTree_singleRef(ctx->server, (UA_NodeId*)eventType.data, operandTypeId,
889
0
                               UA_REFERENCETYPEINDEX_HASSUBTYPE);
890
0
    ctx->operatorResults[index] = t2v(ofType ? UA_TERNARY_TRUE : UA_TERNARY_FALSE);
891
0
    UA_Variant_clear(&eventType);
892
0
    return UA_STATUSCODE_GOOD;
893
0
}
894
895
static UA_StatusCode
896
0
andOperator(UA_FilterEvalContext *ctx, size_t index) {
897
0
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
898
0
    UA_assert(elm->filterOperandsSize == 2);
899
0
    UA_Variant *op0 = pushOperand(ctx);
900
0
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
901
0
    UA_CHECK_STATUS(res, return res);
902
0
    UA_Variant *op1 = pushOperand(ctx);
903
0
    res = resolveOperand(ctx, &elm->filterOperands[1], op1);
904
0
    UA_CHECK_STATUS(res, return res);
905
0
    ctx->operatorResults[index] = t2v(UA_Ternary_and(v2t(op0), v2t(op1)));
906
0
    return UA_STATUSCODE_GOOD;
907
0
}
908
909
static UA_StatusCode
910
0
orOperator(UA_FilterEvalContext *ctx, size_t index) {
911
0
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
912
0
    UA_assert(elm->filterOperandsSize == 2);
913
0
    UA_Variant *op0 = pushOperand(ctx);
914
0
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
915
0
    UA_CHECK_STATUS(res, return res);
916
0
    UA_Variant *op1 = pushOperand(ctx);
917
0
    res = resolveOperand(ctx, &elm->filterOperands[1], op1);
918
0
    UA_CHECK_STATUS(res, return res);
919
0
    ctx->operatorResults[index] = t2v(UA_Ternary_or(v2t(op0), v2t(op1)));
920
0
    return UA_STATUSCODE_GOOD;
921
0
}
922
923
static UA_StatusCode
924
0
notOperator(UA_FilterEvalContext *ctx, size_t index) {
925
0
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
926
0
    UA_assert(elm->filterOperandsSize == 1);
927
0
    UA_Variant *op0 = pushOperand(ctx);
928
0
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
929
0
    UA_CHECK_STATUS(res, return res);
930
0
    ctx->operatorResults[index] = t2v(UA_Ternary_not(v2t(op0)));
931
0
    return UA_STATUSCODE_GOOD;
932
0
}
933
934
/* Resolves the operands and casts them implicitly to the same type. The result
935
 * is set at &ctx->operandStack[ctx->top] (for the initial value of top). */
936
static UA_StatusCode
937
0
castResolveOperands(UA_FilterEvalContext *ctx, size_t index, UA_Boolean setError) {
938
    /* Enough space on the operand stack left? */
939
0
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
940
0
    if(ctx->top + elm->filterOperandsSize > UA_EVENTFILTER_MAXOPERANDS)
941
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
942
943
    /* Resolve all operands */
944
0
    UA_assert(ctx->top == 0); /* Assume the operand stack is empty */
945
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
946
0
    for(size_t i = 0; i < elm->filterOperandsSize; i++) {
947
0
        res = resolveOperand(ctx, &elm->filterOperands[i], pushOperand(ctx));
948
0
        UA_CHECK_STATUS(res, return res);
949
0
    }
950
0
    UA_assert(ctx->top > 0); /* Assume the operand stack is no longer empty */
951
952
    /* Get the datatype for casting */
953
0
    const UA_DataType *targetType = ctx->operandStack[0].type;
954
0
    for(size_t pos = 1; pos < ctx->top; pos++) {
955
0
        if(targetType)
956
0
            targetType = implicitCastTargetType(targetType, ctx->operandStack[pos].type);
957
0
        if(!targetType)
958
0
            return UA_STATUSCODE_BADFILTEROPERANDINVALID;
959
0
    }
960
961
    /* Cast the operands. Put the result in the same location on the operand stack. */
962
0
    for(size_t pos = 0; pos < ctx->top; pos++) {
963
0
        UA_Variant orig = ctx->operandStack[pos];
964
0
        UA_Variant_init(&ctx->operandStack[pos]);
965
0
        res = castImplicit(&orig, targetType, &ctx->operandStack[pos]);
966
0
        if(ctx->operandStack[pos].data == orig.data) {
967
            /* Reuse the storage type of the original data if the variant is
968
             * identical or only the type has changed */
969
0
            ctx->operandStack[pos].storageType = orig.storageType;
970
0
        } else {
971
0
            UA_Variant_clear(&orig); /* Fresh allocation of the cast variant. Clean up. */
972
0
        }
973
0
        if(res != UA_STATUSCODE_GOOD)
974
0
            return res;
975
0
    }
976
977
0
    return UA_STATUSCODE_GOOD;
978
0
}
979
980
static UA_StatusCode
981
0
compareOperator(UA_FilterEvalContext *ctx, size_t index, UA_FilterOperator op) {
982
0
    UA_assert(ctx->filter.whereClause.elements[index].filterOperandsSize == 2);
983
984
    /* Resolve and cast the operands. A failed casting results in FALSE. Note
985
     * that operands could cast to NULL. */
986
0
    UA_assert(ctx->top == 0); /* Assume the operand stack is empty */
987
0
    UA_StatusCode res = castResolveOperands(ctx, index, false);
988
0
    if(res != UA_STATUSCODE_GOOD || !ctx->operandStack[0].type ||
989
0
       ctx->operandStack[0].type != ctx->operandStack[1].type) {
990
0
        ctx->operatorResults[index] = t2v(UA_TERNARY_FALSE);
991
0
        return UA_STATUSCODE_GOOD;
992
0
    }
993
0
    UA_assert(ctx->top == 2); /* Assume the operand stack is no longer empty */
994
995
    /* The equals operator is always possible. For the other comparisons it has
996
     * to be an ordered type: Numerical, Boolean, StatusCode or DateTime. */
997
0
    const UA_DataType *type = ctx->operandStack[0].type;
998
0
    if(op != UA_FILTEROPERATOR_EQUALS && !UA_DataType_isNumeric(type) &&
999
0
       type->typeKind != UA_DATATYPEKIND_BOOLEAN &&
1000
0
       type->typeKind != UA_DATATYPEKIND_STATUSCODE &&
1001
0
       type->typeKind != UA_DATATYPEKIND_DATETIME)
1002
0
        return UA_STATUSCODE_BADFILTEROPERANDINVALID;
1003
1004
    /* Compute the order */
1005
0
    UA_Order eq = UA_order(ctx->operandStack[0].data, ctx->operandStack[1].data, type);
1006
0
    UA_Ternary operatorResult = UA_TERNARY_FALSE;
1007
0
    switch(op) {
1008
0
    case UA_FILTEROPERATOR_EQUALS:
1009
0
    default:
1010
0
        if(eq == UA_ORDER_EQ)
1011
0
            operatorResult = UA_TERNARY_TRUE;
1012
0
        break;
1013
0
    case UA_FILTEROPERATOR_GREATERTHAN:
1014
0
        if(eq == UA_ORDER_MORE)
1015
0
            operatorResult = UA_TERNARY_TRUE;
1016
0
        break;
1017
0
    case UA_FILTEROPERATOR_LESSTHAN:
1018
0
        if(eq == UA_ORDER_LESS)
1019
0
            operatorResult = UA_TERNARY_TRUE;
1020
0
        break;
1021
0
    case UA_FILTEROPERATOR_GREATERTHANOREQUAL:
1022
0
        if(eq == UA_ORDER_MORE || eq == UA_ORDER_EQ)
1023
0
            operatorResult = UA_TERNARY_TRUE;
1024
0
        break;
1025
0
    case UA_FILTEROPERATOR_LESSTHANOREQUAL:
1026
0
        if(eq == UA_ORDER_LESS || eq == UA_ORDER_EQ)
1027
0
            operatorResult = UA_TERNARY_TRUE;
1028
0
        break;
1029
0
    }
1030
1031
    /* Set result as a literal value */
1032
0
    ctx->operatorResults[index] = t2v(operatorResult);
1033
0
    return UA_STATUSCODE_GOOD;
1034
0
}
1035
1036
static UA_StatusCode
1037
0
equalsOperator(UA_FilterEvalContext *ctx, size_t index) {
1038
0
    return compareOperator(ctx, index, UA_FILTEROPERATOR_EQUALS);
1039
0
}
1040
1041
static UA_StatusCode
1042
0
gtOperator(UA_FilterEvalContext *ctx, size_t index) {
1043
0
    return compareOperator(ctx, index, UA_FILTEROPERATOR_GREATERTHAN);
1044
0
}
1045
1046
static UA_StatusCode
1047
0
ltOperator(UA_FilterEvalContext *ctx, size_t index) {
1048
0
    return compareOperator(ctx, index, UA_FILTEROPERATOR_LESSTHAN);
1049
0
}
1050
1051
static UA_StatusCode
1052
0
gteOperator(UA_FilterEvalContext *ctx, size_t index) {
1053
0
    return compareOperator(ctx, index, UA_FILTEROPERATOR_GREATERTHANOREQUAL);
1054
0
}
1055
1056
static UA_StatusCode
1057
0
lteOperator(UA_FilterEvalContext *ctx, size_t index) {
1058
0
    return compareOperator(ctx, index, UA_FILTEROPERATOR_LESSTHANOREQUAL);
1059
0
}
1060
1061
static UA_StatusCode
1062
0
bitwiseOperator(UA_FilterEvalContext *ctx, size_t index, UA_FilterOperator op) {
1063
0
    UA_assert(ctx->filter.whereClause.elements[index].filterOperandsSize == 2);
1064
1065
    /* Resolve and cast the operands. Note that operands could cast to NULL. */
1066
0
    UA_assert(ctx->top == 0); /* Assume the operand stack is empty */
1067
0
    UA_StatusCode res = castResolveOperands(ctx, index, true);
1068
0
    UA_CHECK_STATUS(res, return res);
1069
0
    UA_assert(ctx->top == 2); /* Assume we have two elements */
1070
1071
    /* Operands can cast to NULL */
1072
0
    const UA_DataType *type = ctx->operandStack[0].type;
1073
0
    if(!type || !UA_DataType_isNumeric(type) ||
1074
0
       ctx->operandStack[0].type != ctx->operandStack[1].type)
1075
0
        return UA_STATUSCODE_BADTYPEMISMATCH;
1076
1077
    /* Copy the casted literal to the result */
1078
0
    res = UA_Variant_copy(&ctx->operandStack[0], &ctx->operatorResults[index]);
1079
0
    UA_CHECK_STATUS(res, return res);
1080
1081
    /* Do the bitwise operation on the result data */
1082
0
    UA_Byte *bytesOut = (UA_Byte*)ctx->operatorResults[index].data;
1083
0
    const UA_Byte *bytes2 = (const UA_Byte*)ctx->operandStack[1].data;
1084
0
    for(size_t i = 0; i < type->memSize; i++) {
1085
0
        if(op == UA_FILTEROPERATOR_BITWISEAND)
1086
0
            bytesOut[i] = bytesOut[i] & bytes2[i];
1087
0
        else
1088
0
            bytesOut[i] = bytesOut[i] | bytes2[i];
1089
0
    }
1090
0
    return UA_STATUSCODE_GOOD;
1091
0
}
1092
1093
static UA_StatusCode
1094
0
bitwiseAndOperator(UA_FilterEvalContext *ctx, size_t index) {
1095
0
    return bitwiseOperator(ctx, index, UA_FILTEROPERATOR_BITWISEAND);
1096
0
}
1097
1098
static UA_StatusCode
1099
0
bitwiseOrOperator(UA_FilterEvalContext *ctx, size_t index) {
1100
0
    return bitwiseOperator(ctx, index, UA_FILTEROPERATOR_BITWISEOR);
1101
0
}
1102
1103
static UA_StatusCode
1104
0
betweenOperator(UA_FilterEvalContext *ctx, size_t index) {
1105
0
    UA_assert(ctx->filter.whereClause.elements[index].filterOperandsSize == 3);
1106
1107
    /* If no implicit conversion is available and the operands are of different
1108
     * types, the particular result is FALSE. */
1109
0
    UA_assert(ctx->top == 0); /* Assume the operand stack is empty */
1110
0
    UA_StatusCode res = castResolveOperands(ctx, index, false);
1111
0
    if(res != UA_STATUSCODE_GOOD) {
1112
0
        ctx->operatorResults[index] = t2v(UA_TERNARY_FALSE);
1113
0
        return UA_STATUSCODE_GOOD;
1114
0
    }
1115
0
    UA_assert(ctx->top == 3); /* Assume we have three elements */
1116
1117
    /* The casting can result in NULL values or a non-numerical type */
1118
0
    const UA_DataType *type = ctx->operandStack[0].type;
1119
0
    if(!type || !UA_DataType_isNumeric(type) ||
1120
0
       type != ctx->operandStack[1].type || type != ctx->operandStack[2].type)
1121
0
        return UA_STATUSCODE_BADTYPEMISMATCH;
1122
1123
0
    UA_Order o1 = UA_order(ctx->operandStack[0].data, ctx->operandStack[1].data, type);
1124
0
    UA_Order o2 = UA_order(ctx->operandStack[0].data, ctx->operandStack[2].data, type);
1125
0
    UA_Ternary comp = ((o1 == UA_ORDER_MORE || o1 == UA_ORDER_EQ) &&
1126
0
                       (o2 == UA_ORDER_LESS || o2 == UA_ORDER_EQ)) ?
1127
0
        UA_TERNARY_TRUE : UA_TERNARY_FALSE;
1128
1129
0
    ctx->operatorResults[index] = t2v(comp);
1130
0
    return UA_STATUSCODE_GOOD;
1131
0
}
1132
1133
static UA_StatusCode
1134
0
inListOperator(UA_FilterEvalContext *ctx, size_t index) {
1135
0
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
1136
0
    UA_assert(elm->filterOperandsSize >= 2);
1137
0
    UA_Boolean found = false;
1138
0
    UA_Variant *op0 = pushOperand(ctx);
1139
0
    UA_Variant *op1 = pushOperand(ctx);
1140
0
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
1141
0
    UA_CHECK_STATUS(res, return res);
1142
0
    for(size_t i = 1; i < elm->filterOperandsSize && !found; i++) {
1143
0
        res = resolveOperand(ctx, &elm->filterOperands[i], op1);
1144
0
        if(res != UA_STATUSCODE_GOOD)
1145
0
            continue;
1146
0
        if(UA_Variant_equal(op0, op1))
1147
0
            found = true;
1148
0
        UA_Variant_clear(op1);
1149
0
    }
1150
0
    ctx->operatorResults[index] = t2v((found) ? UA_TERNARY_TRUE: UA_TERNARY_FALSE);
1151
0
    return UA_STATUSCODE_GOOD;
1152
0
}
1153
1154
static UA_StatusCode
1155
0
isNullOperator(UA_FilterEvalContext *ctx, size_t index) {
1156
0
    const UA_ContentFilterElement *elm = &ctx->filter.whereClause.elements[index];
1157
0
    UA_assert(elm->filterOperandsSize == 1);
1158
0
    UA_Variant *op0 = pushOperand(ctx);
1159
0
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
1160
0
    UA_CHECK_STATUS(res, return res);
1161
0
    ctx->operatorResults[index] =
1162
0
        t2v(UA_Variant_isEmpty(op0) ? UA_TERNARY_TRUE : UA_TERNARY_FALSE);
1163
0
    return UA_STATUSCODE_GOOD;
1164
0
}
1165
1166
static UA_StatusCode
1167
0
notImplementedOperator(UA_FilterEvalContext *ctx, size_t index) {
1168
0
    return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
1169
0
}
1170
1171
typedef struct {
1172
    UA_StatusCode (*operatorMethod)(UA_FilterEvalContext *ctx, size_t index);
1173
    UA_Byte minOperatorCount;
1174
    UA_Byte maxOperatorCount;
1175
} UA_FilterOperatorJumptableElement;
1176
1177
static const UA_FilterOperatorJumptableElement operatorJumptable[18] = {
1178
    {equalsOperator, 2, 2},
1179
    {isNullOperator, 1, 1},
1180
    {gtOperator, 2, 2},
1181
    {ltOperator, 2, 2},
1182
    {gteOperator, 2, 2},
1183
    {lteOperator, 2, 2},
1184
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* like */
1185
    {notOperator, 1, 1},
1186
    {betweenOperator, 3, 3},
1187
    {inListOperator, 2, UA_EVENTFILTER_MAXOPERANDS},
1188
    {andOperator, 2, 2},
1189
    {orOperator, 2, 2},
1190
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* cast */
1191
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* in view */
1192
    {ofTypeOperator, 1, 1},
1193
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* related to */
1194
    {bitwiseAndOperator, 2, 2},
1195
    {bitwiseOrOperator, 2, 2}
1196
};
1197
1198
/* Evaluate content filter, exported only for unit testing */
1199
UA_StatusCode
1200
0
evaluateWhereClause(UA_FilterEvalContext *ctx) {
1201
0
    UA_LOCK_ASSERT(&ctx->server->serviceMutex);
1202
1203
    /* An empty filter always succeeds */
1204
0
    if(ctx->filter.whereClause.elementsSize == 0)
1205
0
        return UA_STATUSCODE_GOOD;
1206
1207
    /* Information-model filters may bypass creation-time validation. */
1208
0
    for(size_t i = 0; i < ctx->filter.whereClause.elementsSize; i++) {
1209
0
        if((UA_UInt32)ctx->filter.whereClause.elements[i].filterOperator >
1210
0
           UA_FILTEROPERATOR_BITWISEOR)
1211
0
            return UA_STATUSCODE_BADEVENTFILTERINVALID;
1212
0
    }
1213
1214
    /* Pacify some compilers by initializing the first result */
1215
0
    UA_assert(ctx->top == 0);
1216
0
    UA_Variant_init(&ctx->operatorResults[0]);
1217
1218
    /* Evaluate the filter. Iterate backwards over the filter elements and
1219
     * resolve each. This ensures that all element-index operands point to an
1220
     * evaluated element. */
1221
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
1222
0
    const UA_ContentFilter *cf = &ctx->filter.whereClause;
1223
0
    for(size_t i = cf->elementsSize - 1; i < cf->elementsSize; i--) {
1224
0
        UA_ContentFilterElement *cfe = &cf->elements[i];
1225
0
        res = operatorJumptable[cfe->filterOperator].operatorMethod(ctx, i);
1226
        /* Clean up the operand stack */
1227
0
        for(size_t j = 0; j < ctx->top; j++)
1228
0
            UA_Variant_clear(&ctx->operandStack[j]);
1229
0
        ctx->top = 0;
1230
0
        if(res != UA_STATUSCODE_GOOD)
1231
0
            break;
1232
0
    }
1233
1234
    /* The filter matches if the operator at the first position evaluates to TRUE */
1235
0
    if(res == UA_STATUSCODE_GOOD && v2t(&ctx->operatorResults[0]) != UA_TERNARY_TRUE)
1236
0
        res = UA_STATUSCODE_BADNOMATCH;
1237
1238
    /* Clean up the results stack */
1239
0
    for(size_t i = 0; i < cf->elementsSize; i++)
1240
0
        UA_Variant_clear(&ctx->operatorResults[i]);
1241
0
    return res;
1242
0
}
1243
1244
/*****************************************/
1245
/* Validation of Filters during Creation */
1246
/*****************************************/
1247
1248
/* Initial select clause validation. The following checks are currently performed:
1249
 * - Check if the TypeDefinitionId or BrowsePath of any clause is NULL
1250
 * - Check if the EventType is a subtype of BaseEventType
1251
 * - Check if the AttributeId is valid
1252
 * - Check if the BrowsePath contains null
1253
 * - Check if the IndexRange is defined and if it is parseable
1254
 * - Check if the AttributeId is value when an IndexRange is defined */
1255
UA_StatusCode
1256
UA_SimpleAttributeOperandValidation(UA_Server *server,
1257
0
                                    const UA_SimpleAttributeOperand *sao) {
1258
    /* TypeDefinition is not NULL? */
1259
0
    if(UA_NodeId_isNull(&sao->typeDefinitionId))
1260
0
        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
1261
1262
    /* EventType is a subtype of BaseEventType? */
1263
0
    UA_NodeId baseEventTypeId = UA_NS0ID(BASEEVENTTYPE);
1264
0
    if(!isNodeInTree_singleRef(server, &sao->typeDefinitionId, &baseEventTypeId,
1265
0
                               UA_REFERENCETYPEINDEX_HASSUBTYPE))
1266
0
        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
1267
1268
    /* AttributeId is valid ? */
1269
0
    if(sao->attributeId == 0 || sao->attributeId >= 28)
1270
0
        return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
1271
1272
    /* If the BrowsePath is empty, the Node is the instance of the
1273
     * TypeDefinition. (Part 4, 7.4.4.5) */
1274
0
    if(sao->browsePathSize > 0) {
1275
        /* BrowsePath contains empty BrowseNames? */
1276
0
        for(size_t j = 0; j < sao->browsePathSize; ++j) {
1277
0
            if(UA_QualifiedName_isNull(&sao->browsePath[j]))
1278
0
                return UA_STATUSCODE_BADBROWSENAMEINVALID;
1279
0
        }
1280
1281
        /* Part 4: If the SimpleAttributeOperand is used in an EventFilter and
1282
         * the typeDefinitionId is BaseEventType the Server shall evaluate the
1283
         * browsePath without considering the typeDefinitionId. */
1284
0
        if(!UA_NodeId_equal(&baseEventTypeId, &sao->typeDefinitionId)) {
1285
            /* Part 4: The TypeDefinitionNode restricts the operand to instances
1286
             * of the TypeDefinitionNode or one of its subtypes.
1287
             * First get the list of subtypes from event type (including the
1288
             * event type itself). */
1289
0
            UA_ReferenceTypeSet reftypes_interface =
1290
0
                UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
1291
0
            UA_ExpandedNodeId *childTypeNodes = NULL;
1292
0
            size_t childTypeNodesSize = 0;
1293
0
            UA_StatusCode res =
1294
0
                browseRecursive(server, 1, &sao->typeDefinitionId, UA_BROWSEDIRECTION_FORWARD,
1295
0
                                &reftypes_interface, UA_NODECLASS_OBJECTTYPE, true,
1296
0
                                &childTypeNodesSize, &childTypeNodes);
1297
0
            if(res != UA_STATUSCODE_GOOD)
1298
0
                return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
1299
1300
            /* Is the browse path valid for one of the event types? */
1301
0
            UA_Boolean subTypeContainField = false;
1302
0
            for(size_t j = 0; j < childTypeNodesSize && !subTypeContainField; j++) {
1303
0
                UA_BrowsePathResult bpr =
1304
0
                    browseSimplifiedBrowsePath(server, childTypeNodes[j].nodeId,
1305
0
                                               sao->browsePathSize, sao->browsePath);
1306
1307
0
                if(bpr.statusCode == UA_STATUSCODE_GOOD && bpr.targetsSize > 0)
1308
0
                    subTypeContainField = true;
1309
0
                UA_BrowsePathResult_clear(&bpr);
1310
0
            }
1311
1312
            /* Clean up and return an error if not found */
1313
0
            UA_Array_delete(childTypeNodes, childTypeNodesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
1314
0
            if(!subTypeContainField)
1315
0
                return UA_STATUSCODE_BADNODEIDUNKNOWN;
1316
0
        }
1317
0
    }
1318
1319
    /* IndexRange is defined ? */
1320
0
    if(!UA_String_isEmpty(&sao->indexRange)) {
1321
0
        UA_NumericRange numericRange = UA_NUMERICRANGE("");
1322
0
        if(UA_NumericRange_parse(&numericRange, sao->indexRange) != UA_STATUSCODE_GOOD)
1323
0
            return UA_STATUSCODE_BADINDEXRANGEINVALID;
1324
0
        UA_free(numericRange.dimensions);
1325
1326
        /* AttributeId has to be a value if an IndexRange is defined */
1327
0
        if(sao->attributeId != UA_ATTRIBUTEID_VALUE)
1328
0
            return UA_STATUSCODE_BADTYPEMISMATCH;
1329
0
    }
1330
1331
0
    return UA_STATUSCODE_GOOD;
1332
0
}
1333
1334
/* Initial content filter (where clause) check. Current checks:
1335
 * - Number of operands for each (supported) operator
1336
 * - ElementOperands point forward only */
1337
UA_ContentFilterElementResult
1338
UA_ContentFilterElementValidation(UA_Server *server, size_t operatorIndex,
1339
                                  size_t operatorsCount,
1340
0
                                  const UA_ContentFilterElement *ef) {
1341
    /* Initialize the result structure */
1342
0
    UA_ContentFilterElementResult er;
1343
0
    UA_ContentFilterElementResult_init(&er);
1344
0
    er.operandStatusCodes = (UA_StatusCode *)
1345
0
        UA_Array_new(ef->filterOperandsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
1346
0
    if(!er.operandStatusCodes) {
1347
0
        er.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
1348
0
        return er;
1349
0
    }
1350
0
    er.operandStatusCodesSize = ef->filterOperandsSize;
1351
1352
    /* Is the operator in the defined range? Test this before the following
1353
     * jumptable lookup. */
1354
0
    if(ef->filterOperator < 0 || ef->filterOperator > UA_FILTEROPERATOR_BITWISEOR) {
1355
0
        er.statusCode = UA_STATUSCODE_BADEVENTFILTERINVALID;
1356
0
        return er;
1357
0
    }
1358
1359
    /* Number of operands supported for the operator? */
1360
0
    if(ef->filterOperandsSize < operatorJumptable[ef->filterOperator].minOperatorCount ||
1361
0
       ef->filterOperandsSize > operatorJumptable[ef->filterOperator].maxOperatorCount) {
1362
0
        er.statusCode = UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH;
1363
0
        return er;
1364
0
    }
1365
1366
    /* Generic validation of the operands */
1367
0
    for(size_t i = 0; i < ef->filterOperandsSize; i++) {
1368
        /* Must be a decoded ExtensionObject */
1369
0
        UA_ExtensionObject *op = &ef->filterOperands[i];
1370
0
        if(op->encoding != UA_EXTENSIONOBJECT_DECODED &&
1371
0
           op->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) {
1372
0
            er.operandStatusCodes[i] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
1373
0
            er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
1374
0
            return er;
1375
0
        }
1376
1377
        /* Supported type and conforming to the rules? */
1378
0
        if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) {
1379
            /* Part 4, 7.4.4.2 defines conditions for Element Operands: An index
1380
             * is considered valid if its value is greater than the element
1381
             * index it is part of and it does not Reference a non-existent
1382
             * element. Clients shall construct filters in this way to avoid
1383
             * circular and invalid References. */
1384
0
            UA_ElementOperand *eo = (UA_ElementOperand *)op->content.decoded.data;
1385
0
            if(eo->index <= operatorIndex || eo->index >= operatorsCount) {
1386
0
                er.operandStatusCodes[i] = UA_STATUSCODE_BADINDEXRANGEINVALID;
1387
0
                er.statusCode = UA_STATUSCODE_BADINDEXRANGEINVALID;
1388
0
                return er;
1389
0
            }
1390
0
        } else if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND]) {
1391
0
            er.operandStatusCodes[i] = UA_STATUSCODE_BADNOTSUPPORTED;
1392
0
            er.statusCode = UA_STATUSCODE_BADFILTERNOTALLOWED;
1393
0
            return er;
1394
0
        } else if(op->content.decoded.type != &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND] &&
1395
0
                  op->content.decoded.type != &UA_TYPES[UA_TYPES_LITERALOPERAND]) {
1396
0
            er.operandStatusCodes[i] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
1397
0
            er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
1398
0
            return er;
1399
0
        }
1400
0
    }
1401
1402
    /* Specific validations for different operators */
1403
0
    switch(ef->filterOperator) {
1404
0
        case UA_FILTEROPERATOR_INVIEW:
1405
0
        case UA_FILTEROPERATOR_RELATEDTO:
1406
            /* Not allowed for event WhereClause according to 7.17.3 in Part 4 */
1407
0
            er.statusCode = UA_STATUSCODE_BADEVENTFILTERINVALID;
1408
0
            break;
1409
1410
0
        case UA_FILTEROPERATOR_EQUALS:
1411
0
        case UA_FILTEROPERATOR_GREATERTHAN:
1412
0
        case UA_FILTEROPERATOR_LESSTHAN:
1413
0
        case UA_FILTEROPERATOR_GREATERTHANOREQUAL:
1414
0
        case UA_FILTEROPERATOR_LESSTHANOREQUAL:
1415
0
        case UA_FILTEROPERATOR_BITWISEAND:
1416
0
        case UA_FILTEROPERATOR_BITWISEOR:
1417
0
        case UA_FILTEROPERATOR_BETWEEN:
1418
0
        case UA_FILTEROPERATOR_INLIST:
1419
0
        case UA_FILTEROPERATOR_AND:
1420
0
        case UA_FILTEROPERATOR_OR:
1421
0
        case UA_FILTEROPERATOR_ISNULL:
1422
0
        case UA_FILTEROPERATOR_NOT:
1423
0
            break;
1424
1425
0
        case UA_FILTEROPERATOR_OFTYPE: {
1426
            /* Make sure the operand is a NodeId literal */
1427
0
            UA_ExtensionObject *o = &ef->filterOperands[0];
1428
0
            UA_LiteralOperand *lo = (UA_LiteralOperand *)o->content.decoded.data;
1429
0
            if(o->content.decoded.type != &UA_TYPES[UA_TYPES_LITERALOPERAND] ||
1430
0
               !UA_Variant_hasScalarType(&lo->value, &UA_TYPES[UA_TYPES_NODEID])) {
1431
0
                er.operandStatusCodes[0] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
1432
0
                er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
1433
0
                break;
1434
0
            }
1435
1436
            /* Make sure the operand is a subtype of BaseEventType */
1437
0
            UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
1438
0
            if(!isNodeInTree_singleRef(server, (UA_NodeId *)lo->value.data, &baseEventTypeId,
1439
0
                                       UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
1440
0
                er.operandStatusCodes[0] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
1441
0
                er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
1442
0
                break;
1443
0
            }
1444
0
            break;
1445
0
        }
1446
1447
0
        case UA_FILTEROPERATOR_LIKE:
1448
0
        case UA_FILTEROPERATOR_CAST:
1449
0
            er.statusCode = UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
1450
0
            break;
1451
1452
0
        default:
1453
0
            er.statusCode = UA_STATUSCODE_BADFILTEROPERATORINVALID;
1454
0
            break;
1455
0
    }
1456
0
    return er;
1457
0
}
1458
1459
/*************************/
1460
/* Create Event Instance */
1461
/*************************/
1462
1463
UA_StatusCode
1464
0
evaluateSelectClause(UA_FilterEvalContext *ctx, UA_EventFieldList *efl) {
1465
    /* Nothing to do */
1466
0
    if(ctx->filter.selectClausesSize == 0)
1467
0
        return UA_STATUSCODE_GOOD;
1468
1469
    /* Allocate the event fields list */
1470
0
    efl->eventFields = (UA_Variant*)
1471
0
        UA_calloc(ctx->filter.selectClausesSize, sizeof(UA_Variant));
1472
0
    if(!efl->eventFields)
1473
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1474
0
    efl->eventFieldsSize = ctx->filter.selectClausesSize;
1475
1476
    /* Resolve the select clauses */
1477
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
1478
0
    for(size_t i = 0; i < ctx->filter.selectClausesSize; i++) {
1479
0
        const UA_SimpleAttributeOperand *sao = &ctx->filter.selectClauses[i];
1480
0
        UA_Variant *field = &efl->eventFields[i];
1481
0
        res |= resolveSAO(ctx, sao, field);
1482
1483
        /* Ensure a deep copy */
1484
0
        if(field->storageType == UA_VARIANT_DATA_NODELETE) {
1485
0
            UA_Variant tmp_val;
1486
0
            UA_StatusCode res_ign = UA_Variant_copy(field, &tmp_val);
1487
0
            (void)res_ign; /* Ignore the result - returns an empty variant if copying fails */
1488
0
            *field = tmp_val;
1489
0
        }
1490
0
    }
1491
1492
0
    return res;
1493
0
}
1494
1495
/* Filters an event according to the filter specified by mon and then adds it to
1496
 * mons notification queue */
1497
static UA_StatusCode
1498
0
UA_MonitoredItem_addEvent(UA_MonitoredItem *mon, UA_FilterEvalContext *ctx) {
1499
    /* Evaluate the where clause */
1500
0
    UA_StatusCode res = evaluateWhereClause(ctx);
1501
0
    if(res != UA_STATUSCODE_GOOD) {
1502
0
        if(res == UA_STATUSCODE_BADNOMATCH)
1503
0
            res = UA_STATUSCODE_GOOD;
1504
0
        return res;
1505
0
    }
1506
1507
    /* Allocate memory for the notification */
1508
0
    UA_Notification *n = UA_Notification_new();
1509
0
    if(!n)
1510
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1511
1512
    /* Evaluate the select clause to get the event fields */
1513
0
    res = evaluateSelectClause(ctx, &n->data.event);
1514
0
    if(res != UA_STATUSCODE_GOOD) {
1515
0
        UA_EventFieldList_clear(&n->data.event);
1516
0
        UA_free(n);
1517
0
        return res;
1518
0
    }
1519
1520
    /* Finalize and enqueue the notification */
1521
0
    n->data.event.clientHandle = mon->parameters.clientHandle;
1522
0
    n->mon = mon;
1523
0
    UA_Notification_enqueueAndTrigger(ctx->server, n);
1524
0
    return UA_STATUSCODE_GOOD;
1525
0
}
1526
1527
#ifdef UA_ENABLE_HISTORIZING
1528
static void
1529
setHistoricalEvent(UA_Server *server, const UA_NodeId *emitNode,
1530
0
                   const UA_EventDescription *ed) {
1531
0
    UA_Variant historicalEventFilterValue;
1532
0
    UA_Variant_init(&historicalEventFilterValue);
1533
1534
    /* A HistoricalEventNode that has event history available will provide this property */
1535
0
    UA_StatusCode retval =
1536
0
        readObjectProperty(server, *emitNode,
1537
0
                           UA_QUALIFIEDNAME(0, "HistoricalEventFilter"),
1538
0
                           &historicalEventFilterValue);
1539
0
    if(retval != UA_STATUSCODE_GOOD) {
1540
0
        if(retval != UA_STATUSCODE_BADNOMATCH)
1541
0
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
1542
0
                           "Cannot read the HistoricalEventFilter property of a "
1543
0
                           "listening node. StatusCode %s",
1544
0
                           UA_StatusCode_name(retval));
1545
0
        return;
1546
0
    }
1547
1548
    /* If found then check if HistoricalEventFilter property has a valid value */
1549
0
    if(!UA_Variant_hasScalarType(&historicalEventFilterValue,
1550
0
                                 &UA_TYPES[UA_TYPES_EVENTFILTER])) {
1551
0
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
1552
0
                       "HistoricalEventFilter property of a listening node "
1553
0
                       "does not have a valid value");
1554
0
        UA_Variant_clear(&historicalEventFilterValue);
1555
0
        return;
1556
0
    }
1557
0
    UA_EventFilter *ef = (UA_EventFilter*)historicalEventFilterValue.data;
1558
1559
0
    UA_FilterEvalContext ctx;
1560
0
    UA_FilterEvalContext_init(&ctx);
1561
0
    ctx.server = server;
1562
0
    ctx.session = &server->adminSession;
1563
0
    ctx.filter = *ef;
1564
0
    ctx.ed = *ed;
1565
1566
    /* Evaluate the where clause */
1567
0
    UA_StatusCode res = evaluateWhereClause(&ctx);
1568
0
    if(res != UA_STATUSCODE_GOOD) {
1569
0
        UA_FilterEvalContext_reset(&ctx);
1570
0
        UA_Variant_clear(&historicalEventFilterValue);
1571
0
        return;
1572
0
    }
1573
1574
    /* Get the event fields for the select clause */
1575
0
    UA_EventFieldList efl;
1576
0
    UA_EventFieldList_init(&efl);
1577
0
    res = evaluateSelectClause(&ctx, &efl);
1578
1579
    /* Call the history database backend */
1580
0
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) {
1581
0
        server->config.historyDatabase.
1582
0
            setEvent(server, server->config.historyDatabase.context,
1583
0
                     &ed->sourceNode, emitNode, ef, &efl);
1584
0
    }
1585
1586
0
    UA_FilterEvalContext_reset(&ctx);
1587
0
    UA_Variant_clear(&historicalEventFilterValue);
1588
0
    UA_EventFieldList_clear(&efl);
1589
0
}
1590
#endif
1591
1592
0
#define EMIT_REFS_ROOT_COUNT 4
1593
static const UA_NodeId emitReferencesRoots[EMIT_REFS_ROOT_COUNT] =
1594
    {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}},
1595
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}},
1596
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASEVENTSOURCE}},
1597
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASNOTIFIER}}};
1598
1599
UA_StatusCode
1600
createEvent(UA_Server *server, const UA_EventDescription *ed,
1601
0
            UA_ByteString *outEventId) {
1602
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
1603
0
    UA_LOCK_ASSERT(&server->serviceMutex);
1604
1605
    /* MonitoredItem can only be filtered if the Subscription is defined.
1606
     * Subscription can only be filtered if a Session is defined. */
1607
0
    if((ed->subscriptionId && !ed->sessionId) ||
1608
0
       (ed->monitoredItemId && !ed->subscriptionId)) {
1609
0
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
1610
0
                       "Event shall be created with a filter on Subscription (or MonitoredItem), "
1611
0
                       "but no Session (or Subscription) is defined");
1612
0
        return UA_STATUSCODE_BADINTERNALERROR;
1613
0
    }
1614
1615
0
    UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
1616
0
                 "Events: An event of severity %u is emitted by node %N",
1617
0
                 ed->severity, ed->sourceNode);
1618
1619
#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
1620
    UA_Boolean isCallerAC = false;
1621
    if(isConditionOrBranch(server, &ed->eventType, &ed->sourceNode, &isCallerAC) &&
1622
       !isCallerAC) {
1623
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
1624
                       "Condition Events: Please use A&C API to trigger Condition Events 0x%08X",
1625
                       UA_STATUSCODE_BADINVALIDARGUMENT);
1626
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1627
    }
1628
#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */
1629
1630
    /* The user must ensure that only nodes from the Objects folder (and Views)
1631
     * emit events. The following commented code could enforce this, but is
1632
     * computationally expensive. */
1633
1634
    /* static const UA_NodeId objectsFolderId = */
1635
    /*     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_OBJECTSFOLDER}}; */
1636
    /* static const UA_NodeId isInFolderReferences[2] = */
1637
    /*     {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}}, */
1638
    /*      {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}}}; */
1639
    /* UA_ReferenceTypeSet refTypes; */
1640
    /* UA_ReferenceTypeSet_init(&refTypes); */
1641
    /* for(int i = 0; i < 2; ++i) { */
1642
    /*     UA_ReferenceTypeSet tmpRefTypes; */
1643
    /*     res = referenceTypeIndices(server, &isInFolderReferences[i], &tmpRefTypes, true); */
1644
    /*     if(res != UA_STATUSCODE_GOOD) { */
1645
    /*         UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER, */
1646
    /*                        "Events: Could not create the list of references and their subtypes " */
1647
    /*                        "with StatusCode %s", UA_StatusCode_name(res)); */
1648
    /*     } */
1649
    /*     refTypes = UA_ReferenceTypeSet_union(refTypes, tmpRefTypes); */
1650
    /* } */
1651
    /* if(!isNodeInTree(server, &origin, &objectsFolderId, &refTypes)) { */
1652
    /*     UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_USERLAND, */
1653
    /*                  "Node for event must be in ObjectsFolder!"); */
1654
    /*     return UA_STATUSCODE_BADINVALIDARGUMENT; */
1655
    /* } */
1656
1657
    /* Get all ReferenceTypes over which the events propagate */
1658
0
    UA_ReferenceTypeSet emitRefTypes;
1659
0
    UA_ReferenceTypeSet_init(&emitRefTypes);
1660
0
    for(size_t i = 0; i < EMIT_REFS_ROOT_COUNT; i++) {
1661
0
        UA_ReferenceTypeSet tmpRefTypes;
1662
0
        res = referenceTypeIndices(server, &emitReferencesRoots[i], &tmpRefTypes, true);
1663
0
        if(res != UA_STATUSCODE_GOOD) {
1664
0
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
1665
0
                           "Events: Could not create the list of references for event "
1666
0
                           "propagation with StatusCode %s", UA_StatusCode_name(res));
1667
0
            return res;
1668
0
        }
1669
0
        emitRefTypes = UA_ReferenceTypeSet_union(emitRefTypes, tmpRefTypes);
1670
0
    }
1671
1672
    /* Get the list of nodes in the hierarchy that emits the event. Add the
1673
     * server node to the list of nodes from which the event is emitted. The
1674
     * server node emits all events.
1675
     *
1676
     * Part 3, 7.17: In particular, the root notifier of a Server, the Server
1677
     * Object defined in Part 5, is always capable of supplying all Events from
1678
     * a Server and as such has implied HasEventSource References to every event
1679
     * source in a Server. */
1680
0
    UA_NodeId emitStartNodes[2];
1681
0
    emitStartNodes[0] = ed->sourceNode;
1682
0
    emitStartNodes[1] = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
1683
1684
0
    UA_ExpandedNodeId *emitNodes = NULL;
1685
0
    size_t emitNodesSize = 0;
1686
0
    res = browseRecursive(server, 2, emitStartNodes, UA_BROWSEDIRECTION_INVERSE,
1687
0
                          &emitRefTypes, UA_NODECLASS_UNSPECIFIED, true,
1688
0
                          &emitNodesSize, &emitNodes);
1689
0
    if(res != UA_STATUSCODE_GOOD) {
1690
0
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
1691
0
                       "Events: Could not create the list of nodes listening on the "
1692
0
                       "event with StatusCode %s", UA_StatusCode_name(res));
1693
0
        return res;
1694
0
    }
1695
1696
    /* Set up the eval context. */
1697
0
    UA_FilterEvalContext ctx;
1698
0
    UA_FilterEvalContext_init(&ctx);
1699
0
    ctx.server = server;
1700
0
    ctx.ed = *ed;
1701
    /* ctx.session is set below for each MonitoredItem */
1702
    /* ctx.filter is set below for each MonitoredItem */
1703
1704
    /* Create / resolve the EventId and copy into outEventId */
1705
0
    if(outEventId) {
1706
0
        ctx.session = &server->adminSession;
1707
0
        res = cacheEventId(&ctx);
1708
0
        if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
1709
0
            res = UA_ByteString_copy(&ctx.eventId, outEventId);
1710
0
        UA_FilterEvalContext_reset(&ctx);
1711
0
        if(res != UA_STATUSCODE_GOOD)
1712
0
            return res;
1713
0
    }
1714
1715
    /* Loop over all nodes that emit this event instance */
1716
0
    for(size_t i = 0; i < emitNodesSize; i++) {
1717
        /* We can only emit on local nodes */
1718
0
        if(!UA_ExpandedNodeId_isLocal(&emitNodes[i]))
1719
0
            continue;
1720
1721
        /* Get the node */
1722
0
        const UA_Node *node = UA_NODESTORE_GET(server, &emitNodes[i].nodeId);
1723
0
        if(!node)
1724
0
            continue;
1725
1726
        /* Only consider objects */
1727
0
        if(node->head.nodeClass != UA_NODECLASS_OBJECT) {
1728
0
            UA_NODESTORE_RELEASE(server, node);
1729
0
            continue;
1730
0
        }
1731
1732
        /* Iterate over all MonitoredItems registered in the node  */
1733
0
        UA_MonitoredItem *mon;
1734
0
        LIST_FOREACH(mon, (const UA_MonitoredItemList*)&node->head.monitoredItems,
1735
0
                     sampling.nodeListEntry) {
1736
            /* Is this an Event-MonitoredItem? */
1737
0
            if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER)
1738
0
                continue;
1739
1740
            /* Filter on the Session. If a subscription is not attached to a
1741
             * session, then this filter never matches. */
1742
0
            UA_Subscription *sub = mon->subscription;
1743
0
            if(ed->sessionId && (!sub->session || !UA_NodeId_equal(ed->sessionId, &sub->session->sessionId)))
1744
0
                continue;
1745
1746
            /* Filter on the SubscriptionId */
1747
0
            if(ed->subscriptionId && *ed->subscriptionId != sub->subscriptionId)
1748
0
                continue;
1749
1750
            /* Filter on the MonitoredItemId */
1751
0
            if(ed->monitoredItemId && *ed->monitoredItemId != mon->monitoredItemId)
1752
0
                continue;
1753
1754
            /* Get the EventFilter from the MonitoredItem */
1755
0
            if(!UA_ExtensionObject_hasDecodedType(&mon->parameters.filter,
1756
0
                                                  &UA_TYPES[UA_TYPES_EVENTFILTER])) {
1757
0
                UA_LOG_ERROR_SUBSCRIPTION(server->config.logging, mon->subscription,
1758
0
                                          "MonitoredItem %" PRIi32 " | "
1759
0
                                          "The filter must be an EventFilter", mon->monitoredItemId);
1760
0
                continue;
1761
0
            }
1762
0
            ctx.filter = *(UA_EventFilter*)mon->parameters.filter.content.decoded.data;
1763
1764
            /* Do not evaluate event fields for detached subscriptions.
1765
             * Using adminSession would bypass per-session access control. */
1766
0
            if(!sub->session)
1767
0
                continue;
1768
0
            ctx.session = sub->session;
1769
1770
            /* Evaluate the where-clause and create a notification */
1771
0
            res = UA_MonitoredItem_addEvent(mon, &ctx);
1772
0
            UA_FilterEvalContext_reset(&ctx);
1773
0
            if(res != UA_STATUSCODE_GOOD) {
1774
0
                UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
1775
0
                               "Events: Could not add the event to a listening "
1776
0
                               "node with StatusCode %s", UA_StatusCode_name(res));
1777
0
                res = UA_STATUSCODE_GOOD; /* Only log problems with individual emit nodes */
1778
0
            }
1779
0
        }
1780
1781
0
        UA_NODESTORE_RELEASE(server, node);
1782
1783
        /* Add event entry in the historical database */
1784
0
#ifdef UA_ENABLE_HISTORIZING
1785
0
        if(server->config.historyDatabase.setEvent)
1786
0
            setHistoricalEvent(server, &emitNodes[i].nodeId, ed);
1787
0
#endif
1788
0
    }
1789
1790
    /* Clean up and return */
1791
0
    if(outEventId && res != UA_STATUSCODE_GOOD)
1792
0
        UA_ByteString_clear(outEventId);
1793
0
    UA_Array_delete(emitNodes, emitNodesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
1794
0
    return res;
1795
0
}
1796
1797
UA_StatusCode
1798
UA_Server_createEvent(UA_Server *server, const UA_NodeId sourceNode,
1799
                      const UA_NodeId eventType, UA_UInt16 severity,
1800
                      const UA_LocalizedText message,
1801
                      const UA_KeyValueMap *eventFields,
1802
                      const UA_NodeId *eventInstance,
1803
0
                      UA_ByteString *outEventId) {
1804
0
    UA_EventDescription ed = {0};
1805
0
    ed.sourceNode = sourceNode;
1806
0
    ed.eventType = eventType;
1807
0
    ed.severity = severity;
1808
0
    ed.message = message;
1809
0
    ed.eventFields = eventFields;
1810
0
    ed.eventInstance = eventInstance;
1811
1812
0
    lockServer(server);
1813
0
    UA_StatusCode res = createEvent(server, &ed, outEventId);
1814
0
    unlockServer(server);
1815
0
    return res;
1816
0
}
1817
1818
UA_StatusCode UA_EXPORT UA_THREADSAFE
1819
UA_Server_createEventEx(UA_Server *server,
1820
                        const UA_EventDescription *ed,
1821
0
                        UA_ByteString *outEventId) {
1822
0
    lockServer(server);
1823
0
    UA_StatusCode res = createEvent(server, ed, outEventId);
1824
0
    unlockServer(server);
1825
0
    return res;
1826
0
}
1827
1828
#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */