Coverage Report

Created: 2026-08-14 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/src/pubsub/ua_pubsub_readergroup.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 (c) 2017-2025 Fraunhofer IOSB (Author: Andreas Ebner)
6
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
7
 * Copyright (c) 2019 Kalycito Infotech Private Limited
8
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
9
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
10
 */
11
12
#include <open62541/server_pubsub.h>
13
#include "ua_pubsub_internal.h"
14
15
#ifdef UA_ENABLE_PUBSUB /* conditional compilation */
16
17
#ifdef UA_ENABLE_PUBSUB_SKS
18
#include "ua_pubsub_keystorage.h"
19
#endif
20
21
UA_ReaderGroup *
22
0
UA_ReaderGroup_find(UA_PubSubManager *psm, const UA_NodeId id) {
23
0
    if(!psm)
24
0
        return NULL;
25
0
    UA_PubSubConnection *psc;
26
0
    TAILQ_FOREACH(psc, &psm->connections, listEntry) {
27
0
        UA_ReaderGroup *rg;
28
0
        LIST_FOREACH(rg, &psc->readerGroups, listEntry) {
29
0
            if(UA_NodeId_equal(&id, &rg->head.identifier))
30
0
                return rg;
31
0
        }
32
0
    }
33
0
    return NULL;
34
0
}
35
36
/* ReaderGroup Config Handling */
37
38
UA_StatusCode
39
UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src,
40
0
                          UA_ReaderGroupConfig *dst) {
41
0
    memcpy(dst, src, sizeof(UA_ReaderGroupConfig));
42
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
43
0
    res |= UA_String_copy(&src->name, &dst->name);
44
0
    res |= UA_KeyValueMap_copy(&src->groupProperties, &dst->groupProperties);
45
0
    res |= UA_String_copy(&src->securityGroupId, &dst->securityGroupId);
46
0
    res |= UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings);
47
0
    if(res != UA_STATUSCODE_GOOD)
48
0
        UA_ReaderGroupConfig_clear(dst);
49
0
    return res;
50
0
}
51
52
void
53
0
UA_ReaderGroupConfig_clear(UA_ReaderGroupConfig *readerGroupConfig) {
54
0
    UA_String_clear(&readerGroupConfig->name);
55
0
    UA_KeyValueMap_clear(&readerGroupConfig->groupProperties);
56
0
    UA_String_clear(&readerGroupConfig->securityGroupId);
57
0
    UA_ExtensionObject_clear(&readerGroupConfig->transportSettings);
58
0
}
59
60
61
#ifdef UA_ENABLE_PUBSUB_SKS
62
static UA_StatusCode
63
readerGroupAttachSKSKeystorage(UA_PubSubManager *psm, UA_ReaderGroup *rg) {
64
    /* No SecurityGroup defined */
65
    if(UA_String_isEmpty(&rg->config.securityGroupId) || !rg->config.securityPolicy)
66
        return UA_STATUSCODE_GOOD;
67
68
    /* KeyStorage already connected */
69
    if(rg->keyStorage)
70
        return UA_STATUSCODE_GOOD;
71
72
    /* Does the key storage already exist? */
73
    rg->keyStorage = UA_PubSubKeyStorage_find(psm, rg->config.securityGroupId);
74
    if(rg->keyStorage) {
75
        rg->keyStorage->referenceCount++; /* Increase the ref count */
76
        return UA_STATUSCODE_GOOD;
77
    }
78
79
    /* Create a new key storage */
80
    rg->keyStorage = (UA_PubSubKeyStorage *)UA_calloc(1, sizeof(UA_PubSubKeyStorage));
81
    if(!rg->keyStorage)
82
        return UA_STATUSCODE_BADOUTOFMEMORY;
83
84
    /* Initialize the KeyStorage */
85
    UA_StatusCode res =
86
        UA_PubSubKeyStorage_init(psm, rg->keyStorage, &rg->config.securityGroupId,
87
                                 rg->config.securityPolicy, 0, 0);
88
    if(res != UA_STATUSCODE_GOOD) {
89
        UA_PubSubKeyStorage_delete(psm, rg->keyStorage);
90
        rg->keyStorage = NULL;
91
        return res;
92
    }
93
94
    /* Increase the ref count */
95
    rg->keyStorage->referenceCount++;
96
    return UA_STATUSCODE_GOOD;
97
}
98
#endif
99
100
UA_StatusCode
101
UA_ReaderGroup_create(UA_PubSubManager *psm, UA_NodeId connectionId,
102
                      const UA_ReaderGroupConfig *rgc,
103
0
                      UA_NodeId *readerGroupId) {
104
    /* Check for valid readergroup configuration */
105
0
    if(!psm || !rgc)
106
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
107
108
    /* Search the connection by the given connectionIdentifier */
109
0
    UA_PubSubConnection *c = UA_PubSubConnection_find(psm, connectionId);
110
0
    if(!c)
111
0
        return UA_STATUSCODE_BADNOTFOUND;
112
113
    /* Allocate memory for new reader group and add settings */
114
0
    UA_ReaderGroup *newGroup = (UA_ReaderGroup *)UA_calloc(1, sizeof(UA_ReaderGroup));
115
0
    if(!newGroup)
116
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
117
118
0
    newGroup->head.componentType = UA_PUBSUBCOMPONENT_READERGROUP;
119
0
    newGroup->linkedConnection = c;
120
121
    /* Deep copy of the config */
122
0
    UA_StatusCode retval = UA_ReaderGroupConfig_copy(rgc, &newGroup->config);
123
0
    if(retval != UA_STATUSCODE_GOOD) {
124
0
        UA_free(newGroup);
125
0
        return retval;
126
0
    }
127
128
    /* Add to the connection */
129
0
    LIST_INSERT_HEAD(&c->readerGroups, newGroup, listEntry);
130
0
    c->readerGroupsSize++;
131
132
    /* Cache the log string */
133
0
    char tmpLogIdStr[128];
134
0
    mp_snprintf(tmpLogIdStr, 128, "%SReaderGroup %N\t| ",
135
0
                c->head.logIdString, newGroup->head.identifier);
136
0
    newGroup->head.logIdString = UA_STRING_ALLOC(tmpLogIdStr);
137
138
    /* Validate the connection settings */
139
0
    retval = UA_ReaderGroup_connect(psm, newGroup, true);
140
0
    if(retval != UA_STATUSCODE_GOOD) {
141
0
        UA_LOG_ERROR_PUBSUB(psm->logging, newGroup,
142
0
                            "Could not validate the connection parameters");
143
0
        UA_PubSubComponent_freeWithoutLifecycleCallback(
144
0
            psm, newGroup, UA_PUBSUBCOMPONENT_READERGROUP);
145
0
        return retval;
146
0
    }
147
148
    /* Attach SKS Keystorage */
149
#ifdef UA_ENABLE_PUBSUB_SKS
150
    if(rgc->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
151
       rgc->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
152
        retval = readerGroupAttachSKSKeystorage(psm, newGroup);
153
        if(retval != UA_STATUSCODE_GOOD) {
154
            UA_LOG_ERROR_PUBSUB(psm->logging, newGroup,
155
                                "Attaching the SKS KeyStorage failed");
156
            UA_PubSubComponent_freeWithoutLifecycleCallback(
157
                psm, newGroup, UA_PUBSUBCOMPONENT_READERGROUP);
158
            return retval;
159
        }
160
    }
161
#endif
162
163
    /* Create information model representation */
164
0
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
165
0
    retval |= addReaderGroupRepresentation(psm->sc.server, newGroup);
166
0
    if(retval != UA_STATUSCODE_GOOD) {
167
0
        UA_PubSubComponent_freeWithoutLifecycleCallback(
168
0
            psm, newGroup, UA_PUBSUBCOMPONENT_READERGROUP);
169
0
        return retval;
170
0
    }
171
#else
172
    UA_PubSubManager_generateUniqueNodeId(psm, &newGroup->head.identifier);
173
#endif
174
175
    /* Notify the application that a new ReaderGroup was created.
176
     * This may internally adjust the config */
177
0
    UA_Server *server = psm->sc.server;
178
0
    if(server->config.pubSubConfig.componentLifecycleCallback) {
179
0
        retval = server->config.pubSubConfig.
180
0
            componentLifecycleCallback(server, newGroup->head.identifier,
181
0
                                       UA_PUBSUBCOMPONENT_READERGROUP, false);
182
0
        if(retval != UA_STATUSCODE_GOOD) {
183
            /* The app refused the component; free without re-asking the
184
             * lifecycle callback (it would re-reject and leak the group). */
185
0
            UA_PubSubComponent_freeWithoutLifecycleCallback(
186
0
                psm, newGroup, UA_PUBSUBCOMPONENT_READERGROUP);
187
0
            return retval;
188
0
        }
189
0
    }
190
191
0
    UA_LOG_INFO_PUBSUB(psm->logging, newGroup, "ReaderGroup created (State: %s)",
192
0
                   UA_PubSubState_name(newGroup->head.state));
193
194
    /* Trigger the connection state machine. It might open a socket only when
195
     * the first ReaderGroup is attached. */
196
0
    if(rgc->enabled)
197
0
        UA_PubSubConnection_setPubSubState(psm, c, c->head.state);
198
199
    /* Copying a numeric NodeId always succeeds */
200
0
    if(readerGroupId)
201
0
        UA_NodeId_copy(&newGroup->head.identifier, readerGroupId);
202
203
    /* Enable the ReaderGroup immediately if the enabled flag is set */
204
0
    if(rgc->enabled)
205
0
        UA_ReaderGroup_setPubSubState(psm, newGroup, UA_PUBSUBSTATE_OPERATIONAL);
206
207
0
    return UA_STATUSCODE_GOOD;
208
0
}
209
210
UA_StatusCode
211
0
UA_ReaderGroup_remove(UA_PubSubManager *psm, UA_ReaderGroup *rg) {
212
0
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);
213
214
0
    UA_PubSubConnection *connection = rg->linkedConnection;
215
0
    UA_assert(connection);
216
217
    /* Check with the application if we can remove */
218
0
    UA_Server *server = psm->sc.server;
219
0
    if(server->config.pubSubConfig.componentLifecycleCallback) {
220
0
        UA_StatusCode res = server->config.pubSubConfig.
221
0
            componentLifecycleCallback(server, rg->head.identifier,
222
0
                                       UA_PUBSUBCOMPONENT_READERGROUP, true);
223
0
        if(res != UA_STATUSCODE_GOOD)
224
0
            return res;
225
0
    }
226
227
    /* Disable (and disconnect) and set the deleteFlag. This prevents a
228
     * reconnect and triggers the deletion when the last open socket is
229
     * closed. */
230
0
    rg->deleteFlag = true;
231
0
    UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_DISABLED);
232
233
0
    UA_DataSetReader *dsr, *tmp_dsr;
234
0
    LIST_FOREACH_SAFE(dsr, &rg->readers, listEntry, tmp_dsr) {
235
0
        UA_DataSetReader_remove(psm, dsr);
236
0
    }
237
238
0
    if(rg->config.securityPolicy && rg->securityPolicyContext) {
239
0
        UA_PubSubSecurityPolicy *sp = rg->config.securityPolicy;
240
0
        sp->deleteGroupContext(sp, rg->securityPolicyContext);
241
0
        rg->securityPolicyContext = NULL;
242
0
    }
243
244
#ifdef UA_ENABLE_PUBSUB_SKS
245
    if(rg->keyStorage) {
246
        UA_PubSubKeyStorage_detachKeyStorage(psm, rg->keyStorage);
247
        rg->keyStorage = NULL;
248
    }
249
#endif
250
251
0
    if(rg->recvChannelsSize == 0) {
252
        /* Unlink from the connection */
253
0
        LIST_REMOVE(rg, listEntry);
254
0
        connection->readerGroupsSize--;
255
0
        rg->linkedConnection = NULL;
256
257
        /* Actually remove the ReaderGroup */
258
0
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
259
0
        deleteNode(psm->sc.server, rg->head.identifier, true);
260
0
#endif
261
262
0
        UA_LOG_INFO_PUBSUB(psm->logging, rg, "ReaderGroup deleted");
263
264
0
        UA_ReaderGroupConfig_clear(&rg->config);
265
0
        UA_PubSubComponentHead_clear(&rg->head);
266
0
        UA_free(rg);
267
0
    }
268
269
    /* Update the connection state */
270
0
    UA_PubSubConnection_setPubSubState(psm, connection, connection->head.state);
271
272
0
    return UA_STATUSCODE_GOOD;
273
0
}
274
275
UA_StatusCode
276
UA_ReaderGroup_setPubSubState(UA_PubSubManager *psm, UA_ReaderGroup *rg,
277
0
                              UA_PubSubState targetState) {
278
0
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);
279
280
0
    if(rg->deleteFlag && targetState != UA_PUBSUBSTATE_DISABLED) {
281
0
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
282
0
                              "The ReaderGroup is being deleted. Can only be disabled.");
283
0
        return UA_STATUSCODE_BADINTERNALERROR;
284
0
    }
285
286
    /* Callback to modify the WriterGroup config and change the targetState
287
     * before the state machine executes */
288
0
    UA_Server *server = psm->sc.server;
289
0
    if(server->config.pubSubConfig.beforeStateChangeCallback) {
290
0
        server->config.pubSubConfig.
291
0
            beforeStateChangeCallback(server, rg->head.identifier, &targetState);
292
0
    }
293
294
0
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
295
0
    UA_PubSubState oldState = rg->head.state;
296
0
    UA_PubSubConnection *connection = rg->linkedConnection;
297
298
    /* Are we doing a top-level state update or recursively? */
299
0
    UA_Boolean isTransient = rg->head.transientState;
300
0
    rg->head.transientState = true;
301
302
    /* Custom state machine */
303
0
    if(rg->config.customStateMachine) {
304
0
        ret = rg->config.customStateMachine(server, rg->head.identifier, rg->config.context,
305
0
                                            &rg->head.state, targetState);
306
0
        goto finalize_state_machine;
307
0
    }
308
309
    /* Internal state machine */
310
0
    switch(targetState) {
311
        /* Disabled or Error */
312
0
    case UA_PUBSUBSTATE_DISABLED:
313
0
    case UA_PUBSUBSTATE_ERROR:
314
0
        rg->head.state = targetState;
315
0
        UA_ReaderGroup_disconnect(rg);
316
0
        rg->hasReceived = false;
317
0
        break;
318
319
        /* Enabled */
320
0
    case UA_PUBSUBSTATE_PAUSED:
321
0
    case UA_PUBSUBSTATE_PREOPERATIONAL:
322
0
    case UA_PUBSUBSTATE_OPERATIONAL:
323
0
        if(psm->sc.state != UA_LIFECYCLESTATE_STARTED) {
324
            /* Avoid repeat warnings */
325
0
            if(oldState != UA_PUBSUBSTATE_PAUSED) {
326
0
                UA_LOG_WARNING_PUBSUB(psm->logging, rg,
327
0
                                      "Cannot enable the ReaderGroup while the "
328
0
                                      "server is not running -> Paused State");
329
0
            }
330
0
            rg->head.state = UA_PUBSUBSTATE_PAUSED;
331
0
            UA_ReaderGroup_disconnect(rg);
332
0
            break;
333
0
        }
334
335
        /* Connection is not operational -> ReaderGroup paused */
336
0
        if(connection->head.state != UA_PUBSUBSTATE_OPERATIONAL) {
337
0
            UA_ReaderGroup_disconnect(rg);
338
0
            rg->head.state = UA_PUBSUBSTATE_PAUSED;
339
0
            break;
340
0
        }
341
342
        /* Connect RG-specific connections. For example for MQTT. */
343
0
        if(UA_ReaderGroup_canConnect(rg))
344
0
            ret = UA_ReaderGroup_connect(psm, rg, false);
345
346
        /* Preoperational until a message was received */
347
0
        rg->head.state = (rg->hasReceived) ?
348
0
            UA_PUBSUBSTATE_OPERATIONAL : UA_PUBSUBSTATE_PREOPERATIONAL;
349
0
        break;
350
351
        /* Unknown case */
352
0
    default:
353
0
        ret = UA_STATUSCODE_BADINTERNALERROR;
354
0
        break;
355
0
    }
356
357
    /* Failure */
358
0
    if(ret != UA_STATUSCODE_GOOD) {
359
0
        rg->head.state = UA_PUBSUBSTATE_ERROR;
360
0
        UA_ReaderGroup_disconnect(rg);
361
0
        rg->hasReceived = false;
362
0
    }
363
364
0
 finalize_state_machine:
365
366
    /* Only the top-level state update (if recursive calls are happening)
367
     * notifies the application and updates Reader and WriterGroups */
368
0
    rg->head.transientState = isTransient;
369
0
    if(rg->head.transientState)
370
0
        return ret;
371
372
    /* No state change has happened */
373
0
    if(rg->head.state == oldState)
374
0
        return ret;
375
376
0
    UA_LOG_INFO_PUBSUB(psm->logging, rg, "%s -> %s",
377
0
                       UA_PubSubState_name(oldState),
378
0
                       UA_PubSubState_name(rg->head.state));
379
380
    /* Inform application about state change */
381
0
    if(server->config.pubSubConfig.stateChangeCallback)
382
0
        server->config.pubSubConfig.
383
0
            stateChangeCallback(server, rg->head.identifier, rg->head.state, ret);
384
385
    /* Children evaluate their state machine after the state change of the parent.
386
     * Keep the current child state as the target state for the child. */
387
0
    UA_DataSetReader *dsr;
388
0
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
389
0
        if(psm->pubSubInitialSetupMode && dsr->config.enabled) {
390
0
            UA_DataSetReader_setPubSubState(psm, dsr, UA_PUBSUBSTATE_PREOPERATIONAL, UA_STATUSCODE_GOOD);
391
0
        } else {
392
0
            UA_DataSetReader_setPubSubState(psm, dsr, dsr->head.state, UA_STATUSCODE_GOOD);
393
0
        }
394
0
    }
395
396
    /* Update the PubSubManager state. It will go from STOPPING to STOPPED when
397
     * the last socket has closed. */
398
0
    UA_PubSubManager_setState(psm, psm->sc.state);
399
400
0
    return ret;
401
0
}
402
403
UA_StatusCode
404
UA_ReaderGroup_setEncryptionKeys(UA_PubSubManager *psm, UA_ReaderGroup *rg,
405
                                 UA_UInt32 securityTokenId,
406
                                 const UA_ByteString signingKey,
407
                                 const UA_ByteString encryptingKey,
408
0
                                 const UA_ByteString keyNonce) {
409
0
    if(rg->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) {
410
0
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
411
0
                              "JSON encoding is enabled. The message security is "
412
0
                              "only defined for the UADP message mapping.");
413
0
        return UA_STATUSCODE_BADINTERNALERROR;
414
0
    }
415
416
0
    UA_PubSubSecurityPolicy *sp = rg->config.securityPolicy;
417
0
    if(!sp) {
418
0
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
419
0
                              "No SecurityPolicy configured for the ReaderGroup");
420
0
        return UA_STATUSCODE_BADINTERNALERROR;
421
0
    }
422
423
0
    if(securityTokenId != rg->securityTokenId) {
424
0
        rg->securityTokenId = securityTokenId;
425
0
        rg->nonceSequenceNumber = 1;
426
0
    }
427
428
    /* Create a new context */
429
0
    if(!rg->securityPolicyContext) {
430
0
        return sp->newGroupContext(sp, &signingKey, &encryptingKey, &keyNonce,
431
0
                                   &rg->securityPolicyContext);
432
0
    }
433
434
    /* Update the context */
435
0
    return sp->setSecurityKeys(sp, rg->securityPolicyContext, &signingKey,
436
0
                               &encryptingKey, &keyNonce);
437
0
}
438
439
UA_Boolean
440
UA_ReaderGroup_process(UA_PubSubManager *psm, UA_ReaderGroup *rg,
441
0
                       UA_NetworkMessage *nm) {
442
    /* Check if the ReaderGroup is enabled */
443
0
    if(rg->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
444
0
       rg->head.state != UA_PUBSUBSTATE_PREOPERATIONAL)
445
0
        return false;
446
447
    /* Set to operational if required */
448
0
    rg->hasReceived = true;
449
0
    UA_ReaderGroup_setPubSubState(psm, rg, rg->head.state);
450
451
    /* Safe iteration. The current Reader might be deleted in the ReaderGroup
452
     * _setPubSubState callback. */
453
0
    UA_Boolean processed = false;
454
0
    UA_DataSetReader *reader, *reader_tmp;
455
0
    LIST_FOREACH_SAFE(reader, &rg->readers, listEntry, reader_tmp) {
456
        /* Check if the reader is enabled */
457
0
        if(reader->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
458
0
           reader->head.state != UA_PUBSUBSTATE_PREOPERATIONAL)
459
0
            continue;
460
461
0
        UA_StatusCode res = UA_DataSetReader_checkIdentifier(psm, reader, nm);
462
0
        if(res != UA_STATUSCODE_GOOD)
463
0
            continue;
464
465
        /* Update the ReaderGroup state if this is the first received message */
466
0
        if(!rg->hasReceived) {
467
0
            rg->hasReceived = true;
468
0
            UA_ReaderGroup_setPubSubState(psm, rg, rg->head.state);
469
0
        }
470
471
        /* The message was processed by at least one reader */
472
0
        processed = true;
473
474
0
        UA_LOG_TRACE_PUBSUB(psm->logging, rg, "Processing a NetworkMessage");
475
476
        /* No payload header. The message ontains a single DataSetMessage that
477
         * is processed by every Reader. */
478
0
        if(!nm->payloadHeaderEnabled) {
479
0
            UA_DataSetReader_process(psm, reader, nm->payload.dataSetMessages);
480
0
            continue;
481
0
        }
482
483
        /* Process only the payloads where the WriterId from the header is expected */
484
0
        for(size_t i = 0; i < nm->messageCount; i++) {
485
0
            if(reader->config.dataSetWriterId == nm->dataSetWriterIds[i])
486
0
                UA_DataSetReader_process(psm, reader, &nm->payload.dataSetMessages[i]);
487
0
        }
488
0
    }
489
490
0
    return processed;
491
0
}
492
493
UA_StatusCode
494
UA_ReaderGroup_decodeNetworkMessage(UA_PubSubManager *psm,
495
                                    UA_ReaderGroup *rg,
496
                                    UA_ByteString buffer,
497
0
                                    UA_NetworkMessage *nm) {
498
    /* Set up the decoding context */
499
0
    PubSubDecodeCtx ctx;
500
0
    memset(&ctx, 0, sizeof(PubSubDecodeCtx));
501
0
    ctx.ctx.pos = buffer.data;
502
0
    ctx.ctx.end = buffer.data + buffer.length;
503
0
    ctx.ctx.opts.customTypes = psm->sc.server->config.customDataTypes;
504
505
    /* Decode the headers. This sets the number of DataSetMessages and retrieves
506
     * the DataSetWriterIds. Those get matched to the readers below. */
507
0
    UA_StatusCode rv = UA_NetworkMessage_decodeHeaders(&ctx, nm);
508
0
    if(rv != UA_STATUSCODE_GOOD) {
509
0
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
510
0
                              "PubSub receive. decoding headers failed");
511
0
        UA_NetworkMessage_clear(nm);
512
0
        return rv;
513
0
    }
514
515
    /* Find a matching reader. Otherwise skip for this ReaderGroup */
516
0
    UA_DataSetReader *dsr;
517
0
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
518
0
        rv = UA_DataSetReader_checkIdentifier(psm, dsr, nm);
519
0
        if(rv == UA_STATUSCODE_GOOD)
520
0
            break;
521
0
    }
522
0
    if(!dsr) {
523
0
        UA_NetworkMessage_clear(nm);
524
0
        return UA_STATUSCODE_BADNOTFOUND;
525
0
    }
526
527
    /* Prepare the metadata with information from the readers to decode the
528
     * DataSetMessages */
529
0
    size_t i = 0;
530
0
    UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, rg->readersCount);
531
0
    memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * rg->readersCount);
532
0
    ctx.eo.metaData = emd;
533
0
    ctx.eo.metaDataSize = rg->readersCount;
534
0
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
535
0
        emd[i].dataSetWriterId = dsr->config.dataSetWriterId;
536
0
        emd[i].fields = dsr->config.dataSetMetaData.fields;
537
0
        emd[i].fieldsSize = dsr->config.dataSetMetaData.fieldsSize;
538
0
        i++;
539
0
    }
540
541
    /* Handle missing payload header and "inject" metadata */
542
0
    if(!nm->payloadHeaderEnabled) {
543
0
        rv = UA_NetworkMessage_makeSyntheticPayloadHeader(&ctx.eo, nm);
544
0
        if(rv != UA_STATUSCODE_GOOD) {
545
0
            UA_NetworkMessage_clear(nm);
546
0
            return rv;
547
0
        }
548
0
    }
549
550
    /* Decrypt */
551
0
    rv = verifyAndDecryptNetworkMessage(psm->logging, buffer, &ctx.ctx, nm, rg);
552
0
    if(rv != UA_STATUSCODE_GOOD) {
553
0
        UA_NetworkMessage_clear(nm);
554
0
        return rv;
555
0
    }
556
557
    /* Decode the payload */
558
0
    rv = UA_NetworkMessage_decodePayload(&ctx, nm);
559
0
    if(rv != UA_STATUSCODE_GOOD) {
560
0
        UA_NetworkMessage_clear(nm);
561
0
        return rv;
562
0
    }
563
564
0
    rv = UA_NetworkMessage_decodeFooters(&ctx, nm);
565
0
    if(rv != UA_STATUSCODE_GOOD) {
566
0
        UA_NetworkMessage_clear(nm);
567
0
        return rv;
568
0
    }
569
570
0
    return UA_STATUSCODE_GOOD;
571
0
}
572
573
#ifdef UA_ENABLE_JSON_ENCODING
574
UA_StatusCode
575
UA_ReaderGroup_decodeNetworkMessageJSON(UA_PubSubManager *psm,
576
                                        UA_ReaderGroup *rg,
577
                                        UA_ByteString buffer,
578
0
                                        UA_NetworkMessage *nm) {
579
    /* Set up the decoding options */
580
0
    UA_DecodeJsonOptions jo;
581
0
    memset(&jo, 0, sizeof(jo));
582
0
    jo.customTypes = psm->sc.server->config.customDataTypes;
583
584
    /* Prepare the metadata with information from the readers to decode the
585
     * DataSetMessages */
586
0
    UA_NetworkMessage_EncodingOptions eo;
587
0
    size_t i = 0;
588
0
    UA_STACKARRAY(UA_DataSetMessage_EncodingMetaData, emd, rg->readersCount);
589
0
    memset(emd, 0, sizeof(UA_DataSetMessage_EncodingMetaData) * rg->readersCount);
590
0
    eo.metaData = emd;
591
0
    eo.metaDataSize = rg->readersCount;
592
593
0
    UA_DataSetReader *dsr;
594
0
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
595
0
        emd[i].dataSetWriterId = dsr->config.dataSetWriterId;
596
0
        emd[i].fields = dsr->config.dataSetMetaData.fields;
597
0
        emd[i].fieldsSize = dsr->config.dataSetMetaData.fieldsSize;
598
0
        i++;
599
0
    }
600
601
    /* Decode */
602
0
    return UA_NetworkMessage_decodeJson(&buffer, nm, &eo, &jo);
603
0
}
604
#endif
605
606
/******************************/
607
/* Decrypt the NetworkMessage */
608
/******************************/
609
610
static UA_StatusCode
611
needsDecryption(const UA_Logger *logger,
612
                const UA_NetworkMessage *networkMessage,
613
                const UA_MessageSecurityMode securityMode,
614
0
                UA_Boolean *doDecrypt) {
615
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
616
0
    UA_Boolean requiresEncryption = securityMode > UA_MESSAGESECURITYMODE_SIGN;
617
0
    UA_Boolean isEncrypted = networkMessage->securityHeader.networkMessageEncrypted;
618
619
0
    if(isEncrypted && requiresEncryption) {
620
0
        *doDecrypt = true;
621
0
    } else if(!isEncrypted && !requiresEncryption) {
622
0
        *doDecrypt = false;
623
0
    } else {
624
0
        if(isEncrypted) {
625
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURITYPOLICY,
626
0
                         "PubSub receive. "
627
0
                         "Message is encrypted but ReaderGroup does not expect encryption");
628
0
            retval = UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT;
629
0
        } else {
630
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURITYPOLICY,
631
0
                         "PubSub receive. "
632
0
                         "Message is not encrypted but ReaderGroup requires encryption");
633
0
            retval = UA_STATUSCODE_BADSECURITYMODEREJECTED;
634
0
        }
635
0
    }
636
0
    return retval;
637
0
}
638
639
static UA_StatusCode
640
needsValidation(const UA_Logger *logger,
641
                const UA_NetworkMessage *networkMessage,
642
                const UA_MessageSecurityMode securityMode,
643
0
                UA_Boolean *doValidate) {
644
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
645
0
    UA_Boolean isSigned = networkMessage->securityHeader.networkMessageSigned;
646
0
    UA_Boolean requiresSignature = securityMode > UA_MESSAGESECURITYMODE_NONE;
647
648
0
    if(isSigned &&
649
0
       requiresSignature) {
650
0
        *doValidate = true;
651
0
    } else if(!isSigned && !requiresSignature) {
652
0
        *doValidate = false;
653
0
    } else {
654
0
        if(isSigned) {
655
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURITYPOLICY,
656
0
                         "PubSub receive. "
657
0
                         "Message is signed but ReaderGroup does not expect signatures");
658
0
            retval = UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT;
659
0
        } else {
660
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURITYPOLICY,
661
0
                         "PubSub receive. "
662
0
                         "Message is not signed but ReaderGroup requires signature");
663
0
            retval = UA_STATUSCODE_BADSECURITYMODEREJECTED;
664
0
        }
665
0
    }
666
0
    return retval;
667
0
}
668
669
UA_StatusCode
670
verifyAndDecryptNetworkMessage(const UA_Logger *logger, UA_ByteString buffer,
671
0
                               Ctx *ctx, UA_NetworkMessage *nm, UA_ReaderGroup *rg) {
672
0
    UA_MessageSecurityMode securityMode = rg->config.securityMode;
673
0
    UA_Boolean doValidate = false;
674
0
    UA_Boolean doDecrypt = false;
675
676
0
    UA_StatusCode rv = needsValidation(logger, nm, securityMode, &doValidate);
677
0
    UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
678
0
                         "PubSub receive. Validation security mode error");
679
680
0
    rv = needsDecryption(logger, nm, securityMode, &doDecrypt);
681
0
    UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
682
0
                         "PubSub receive. Decryption security mode error");
683
684
0
    if(!doValidate && !doDecrypt)
685
0
        return UA_STATUSCODE_GOOD;
686
687
0
    UA_PubSubSecurityPolicy *sp = rg->config.securityPolicy;
688
0
    UA_CHECK_MEM_ERROR(sp, return UA_STATUSCODE_BADINVALIDARGUMENT,
689
0
                       logger, UA_LOGCATEGORY_PUBSUB,
690
0
                       "PubSub receive. securityPolicy must be set when security mode"
691
0
                       "is enabled to sign and/or encrypt");
692
693
0
    void *cc = rg->securityPolicyContext;
694
0
    UA_CHECK_MEM_ERROR(cc, return UA_STATUSCODE_BADINVALIDARGUMENT,
695
0
                       logger, UA_LOGCATEGORY_PUBSUB,
696
0
                       "PubSub receive. securityPolicyContext must be initialized "
697
0
                       "when security mode is enabled to sign and/or encrypt");
698
699
    /* Validate the signature */
700
0
    if(doValidate) {
701
0
        size_t sigSize = sp->getSignatureSize(sp, cc);
702
0
        if(buffer.length < sigSize) {
703
0
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
704
0
                           "PubSub receive. Message too short for signature");
705
0
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
706
0
        }
707
0
        UA_ByteString toBeVerified = {buffer.length - sigSize, buffer.data};
708
0
        UA_ByteString signature = {sigSize, buffer.data + buffer.length - sigSize};
709
710
0
        rv = sp->verify(sp, cc, &toBeVerified, &signature);
711
0
        UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
712
0
                             "PubSub receive. Signature invalid");
713
714
        /* Remove the signature from the ctx->end. We do not want to decode that. */
715
0
        ctx->end -= sigSize;
716
0
    }
717
718
    /* Decrypt the content */
719
0
    if(doDecrypt) {
720
0
        const UA_ByteString nonce = {
721
0
            (size_t)nm->securityHeader.messageNonceSize,
722
0
            (UA_Byte*)(uintptr_t)nm->securityHeader.messageNonce
723
0
        };
724
0
        rv = sp->setMessageNonce(sp, cc, &nonce);
725
0
        UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
726
0
                             "PubSub receive. Faulty Nonce set");
727
728
0
        UA_ByteString toBeDecrypted = {(uintptr_t)(ctx->end - ctx->pos), ctx->pos};
729
0
        rv = sp->decrypt(sp, cc, &toBeDecrypted);
730
0
        UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SECURITYPOLICY,
731
0
                             "PubSub receive. Faulty Decryption");
732
0
    }
733
734
0
    return UA_STATUSCODE_GOOD;
735
0
}
736
737
/***********************/
738
/* Connection Handling */
739
/***********************/
740
741
static UA_StatusCode
742
UA_ReaderGroup_connectMQTT(UA_PubSubManager *psm, UA_ReaderGroup *rg,
743
                           UA_Boolean validate);
744
745
typedef struct  {
746
    UA_String profileURI;
747
    UA_String protocol;
748
    UA_Boolean json;
749
    UA_StatusCode (*connectReaderGroup)(UA_PubSubManager *psm, UA_ReaderGroup *rg,
750
                                        UA_Boolean validate);
751
} ReaderGroupProfileMapping;
752
753
static ReaderGroupProfileMapping readerGroupProfiles[UA_PUBSUB_PROFILES_SIZE] = {
754
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"),
755
     UA_STRING_STATIC("udp"), false, NULL},
756
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-uadp"),
757
     UA_STRING_STATIC("mqtt"), false, UA_ReaderGroup_connectMQTT},
758
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-json"),
759
     UA_STRING_STATIC("mqtt"), true, UA_ReaderGroup_connectMQTT},
760
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"),
761
     UA_STRING_STATIC("eth"), false, NULL}
762
};
763
764
static void
765
UA_ReaderGroup_detachConnection(UA_PubSubManager *psm, UA_ReaderGroup *rg,
766
0
                                UA_ConnectionManager *cm, uintptr_t connectionId) {
767
0
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
768
0
        if(rg->recvChannels[i] != connectionId)
769
0
            continue;
770
0
        UA_LOG_INFO_PUBSUB(psm->logging, rg, "Detach receive-connection %S %u",
771
0
                           cm->protocol, (unsigned)connectionId);
772
0
        rg->recvChannels[i] = 0;
773
0
        rg->recvChannelsSize--;
774
0
        return;
775
0
    }
776
0
}
777
778
static UA_StatusCode
779
UA_ReaderGroup_attachRecvConnection(UA_PubSubManager *psm, UA_ReaderGroup *rg,
780
0
                                    UA_ConnectionManager *cm, uintptr_t connectionId) {
781
0
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
782
0
        if(rg->recvChannels[i] == connectionId)
783
0
            return UA_STATUSCODE_GOOD;
784
0
    }
785
0
    if(rg->recvChannelsSize >= UA_PUBSUB_MAXCHANNELS)
786
0
        return UA_STATUSCODE_BADINTERNALERROR;
787
0
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
788
0
        if(rg->recvChannels[i] != 0)
789
0
            continue;
790
0
        UA_LOG_INFO_PUBSUB(psm->logging, rg, "Attach receive-connection %S %u",
791
0
                           cm->protocol, (unsigned)connectionId);
792
0
        rg->recvChannels[i] = connectionId;
793
0
        rg->recvChannelsSize++;
794
0
        break;
795
0
    }
796
0
    return UA_STATUSCODE_GOOD;
797
0
}
798
799
static void
800
ReaderGroupChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
801
                          void *application, void **connectionContext,
802
                          UA_ConnectionState state, const UA_KeyValueMap *params,
803
0
                          UA_ByteString msg) {
804
0
    if(!connectionContext)
805
0
        return;
806
807
    /* Get the context pointers */
808
0
    UA_ReaderGroup *rg = (UA_ReaderGroup*)*connectionContext;
809
0
    UA_PubSubManager *psm = (UA_PubSubManager*)application;
810
0
    UA_Server *server = psm->sc.server;
811
812
0
    lockServer(server);
813
814
    /* The connection is closing in the EventLoop. This is the last callback
815
     * from that connection. Clean up the SecureChannel in the client. */
816
0
    if(state == UA_CONNECTIONSTATE_CLOSING) {
817
        /* Reset the connection identifiers */
818
0
        UA_ReaderGroup_detachConnection(psm, rg, cm, connectionId);
819
820
        /* PSC marked for deletion and the last EventLoop connection has closed */
821
0
        if(rg->deleteFlag && rg->recvChannelsSize == 0) {
822
0
            UA_ReaderGroup_remove(psm, rg);
823
0
            unlockServer(server);
824
0
            return;
825
0
        }
826
827
        /* Reconnect if still operational */
828
0
        UA_ReaderGroup_setPubSubState(psm, rg, rg->head.state);
829
830
        /* Switch the psm state from stopping to stopped once the last
831
         * connection has closed */
832
0
        UA_PubSubManager_setState(psm, psm->sc.state);
833
834
0
        unlockServer(server);
835
0
        return;
836
0
    }
837
838
    /* Store the connectionId (if a new connection) */
839
0
    UA_StatusCode res = UA_ReaderGroup_attachRecvConnection(psm, rg, cm, connectionId);
840
0
    if(res != UA_STATUSCODE_GOOD) {
841
0
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
842
0
                              "No more space for an additional EventLoop connection");
843
0
        UA_PubSubConnection *c = rg->linkedConnection;
844
0
        if(c && c->cm)
845
0
            c->cm->closeConnection(c->cm, connectionId);
846
0
        unlockServer(server);
847
0
        return;
848
0
    }
849
850
    /* The connection has opened - set the ReaderGroup to operational */
851
0
    UA_ReaderGroup_setPubSubState(psm, rg, rg->head.state);
852
853
    /* No message received */
854
0
    if(msg.length == 0) {
855
0
        unlockServer(server);
856
0
        return;
857
0
    }
858
859
0
    if (rg->head.state != UA_PUBSUBSTATE_OPERATIONAL &&
860
0
        rg->head.state != UA_PUBSUBSTATE_PREOPERATIONAL) {
861
0
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
862
0
            "Received a message for a disabled ReaderGroup");
863
0
        unlockServer(server);
864
0
        return;
865
0
    }
866
867
    /* Decode message */
868
0
    UA_NetworkMessage nm;
869
0
    memset(&nm, 0, sizeof(UA_NetworkMessage));
870
0
    if(rg->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP) {
871
0
        res = UA_ReaderGroup_decodeNetworkMessage(psm, rg, msg, &nm);
872
0
    } else { /* if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) */
873
0
#ifdef UA_ENABLE_JSON_ENCODING
874
0
        res = UA_ReaderGroup_decodeNetworkMessageJSON(psm, rg, msg, &nm);
875
#else
876
        res = UA_STATUSCODE_BADNOTSUPPORTED;
877
#endif
878
0
    }
879
0
    if(res != UA_STATUSCODE_GOOD) {
880
0
        UA_LOG_WARNING_PUBSUB(psm->logging, rg,
881
0
                              "Verify, decrypt and decode network message failed");
882
0
        unlockServer(server);
883
0
        return;
884
0
    }
885
886
    /* Process the decoded message */
887
0
    UA_ReaderGroup_process(psm, rg, &nm);
888
0
    UA_NetworkMessage_clear(&nm);
889
0
    unlockServer(server);
890
0
}
891
892
static UA_StatusCode
893
UA_ReaderGroup_connectMQTT(UA_PubSubManager *psm, UA_ReaderGroup *rg,
894
0
                           UA_Boolean validate) {
895
0
    UA_LOCK_ASSERT(&psm->sc.server->serviceMutex);
896
897
0
    UA_PubSubConnection *c = rg->linkedConnection;
898
0
    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType*)
899
0
        c->config.address.data;
900
901
    /* Get the TransportSettings */
902
0
    UA_ExtensionObject *ts = &rg->config.transportSettings;
903
0
    if((ts->encoding != UA_EXTENSIONOBJECT_DECODED &&
904
0
        ts->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
905
0
       ts->content.decoded.type !=
906
0
       &UA_TYPES[UA_TYPES_BROKERDATASETREADERTRANSPORTDATATYPE]) {
907
0
        UA_LOG_ERROR_PUBSUB(psm->logging, rg,
908
0
                            "Wrong TransportSettings type for MQTT");
909
0
        return UA_STATUSCODE_BADINTERNALERROR;
910
0
    }
911
0
    UA_BrokerDataSetReaderTransportDataType *transportSettings =
912
0
        (UA_BrokerDataSetReaderTransportDataType*)ts->content.decoded.data;
913
914
    /* Extract hostname and port */
915
0
    UA_String address;
916
0
    UA_UInt16 port = 1883; /* Default */
917
0
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, &port, NULL);
918
0
    if(res != UA_STATUSCODE_GOOD) {
919
0
        UA_LOG_ERROR_PUBSUB(psm->logging, c, "Could not parse the MQTT network URL");
920
0
        return res;
921
0
    }
922
923
    /* Set up the connection parameters.
924
     * TODO: Complete the MQTT parameters. */
925
0
    UA_Boolean listen = true;
926
0
    UA_KeyValuePair kvp[5];
927
0
    UA_KeyValueMap kvm = {5, kvp};
928
0
    kvp[0].key = UA_QUALIFIEDNAME(0, "address");
929
0
    UA_Variant_setScalar(&kvp[0].value, &address, &UA_TYPES[UA_TYPES_STRING]);
930
0
    kvp[1].key = UA_QUALIFIEDNAME(0, "subscribe");
931
0
    UA_Variant_setScalar(&kvp[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
932
0
    kvp[2].key = UA_QUALIFIEDNAME(0, "port");
933
0
    UA_Variant_setScalar(&kvp[2].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
934
0
    kvp[3].key = UA_QUALIFIEDNAME(0, "topic");
935
0
    UA_Variant_setScalar(&kvp[3].value, &transportSettings->queueName,
936
0
                         &UA_TYPES[UA_TYPES_STRING]);
937
0
    kvp[4].key = UA_QUALIFIEDNAME(0, "validate");
938
0
    UA_Variant_setScalar(&kvp[4].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);
939
940
    /* Connect */
941
0
    res = c->cm->openConnection(c->cm, &kvm, psm, rg, ReaderGroupChannelCallback);
942
0
    if(res != UA_STATUSCODE_GOOD) {
943
0
        UA_LOG_ERROR_PUBSUB(psm->logging, rg, "Could not open the MQTT connection");
944
0
    }
945
0
    return res;
946
0
}
947
948
void
949
0
UA_ReaderGroup_disconnect(UA_ReaderGroup *rg) {
950
0
    UA_PubSubConnection *c = rg->linkedConnection;
951
0
    if(!c)
952
0
        return;
953
0
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
954
0
        if(rg->recvChannels[i] != 0)
955
0
            c->cm->closeConnection(c->cm, rg->recvChannels[i]);
956
0
    }
957
0
}
958
959
UA_Boolean
960
0
UA_ReaderGroup_canConnect(UA_ReaderGroup *rg) {
961
0
    return rg->recvChannelsSize == 0;
962
0
}
963
964
UA_StatusCode
965
0
UA_ReaderGroup_connect(UA_PubSubManager *psm, UA_ReaderGroup *rg, UA_Boolean validate) {
966
0
    UA_Server *server = psm->sc.server;
967
0
    UA_LOCK_ASSERT(&server->serviceMutex);
968
969
    /* Is this a ReaderGroup with custom TransportSettings beyond the
970
     * PubSubConnection? */
971
0
    if(rg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
972
0
        return UA_STATUSCODE_GOOD;
973
974
0
    UA_EventLoop *el = psm->sc.server->config.eventLoop;
975
0
    if(!el) {
976
0
        UA_LOG_ERROR_PUBSUB(server->config.logging, rg, "No EventLoop configured");
977
0
        return UA_STATUSCODE_BADINTERNALERROR;
978
0
    }
979
980
0
    UA_PubSubConnection *c = rg->linkedConnection;
981
0
    if(!c)
982
0
        return UA_STATUSCODE_BADINTERNALERROR;
983
984
    /* Look up the connection manager for the connection */
985
0
    ReaderGroupProfileMapping *profile = NULL;
986
0
    for(size_t i = 0; i < UA_PUBSUB_PROFILES_SIZE; i++) {
987
0
        if(!UA_String_equal(&c->config.transportProfileUri,
988
0
                            &readerGroupProfiles[i].profileURI))
989
0
            continue;
990
0
        profile = &readerGroupProfiles[i];
991
0
        break;
992
0
    }
993
994
0
    UA_ConnectionManager *cm = (profile) ? getCM(el, profile->protocol) : NULL;
995
0
    if(!cm || (c->cm && cm != c->cm)) {
996
0
        UA_LOG_ERROR_PUBSUB(psm->logging, c,
997
0
                            "The requested profile \"%S\"is not supported",
998
0
                            c->config.transportProfileUri);
999
0
        return UA_STATUSCODE_BADINTERNALERROR;
1000
0
    }
1001
1002
0
    c->cm = cm;
1003
0
    c->json = profile->json;
1004
1005
    /* If no ReaderGroup-specific connections, the ReaderGroup is set to
1006
     * operational when we return. */
1007
0
    return (profile->connectReaderGroup) ?
1008
0
        profile->connectReaderGroup(psm, rg, validate) : UA_STATUSCODE_GOOD;
1009
0
}
1010
1011
/**************/
1012
/* Server API */
1013
/**************/
1014
1015
UA_StatusCode
1016
UA_Server_addReaderGroup(UA_Server *server, const UA_NodeId connectionIdentifier,
1017
                         const UA_ReaderGroupConfig *readerGroupConfig,
1018
0
                         UA_NodeId *readerGroupIdentifier) {
1019
0
    if(!server || !readerGroupConfig)
1020
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1021
0
    lockServer(server);
1022
0
    UA_PubSubManager *psm = getPSM(server);
1023
0
    UA_StatusCode res =
1024
0
        UA_ReaderGroup_create(psm, connectionIdentifier,
1025
0
                              readerGroupConfig, readerGroupIdentifier);
1026
0
    unlockServer(server);
1027
0
    return res;
1028
0
}
1029
1030
UA_StatusCode
1031
0
UA_Server_removeReaderGroup(UA_Server *server, const UA_NodeId groupIdentifier) {
1032
0
    if(!server)
1033
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1034
0
    lockServer(server);
1035
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
1036
0
    UA_PubSubManager *psm = getPSM(server);
1037
0
    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, groupIdentifier);
1038
0
    if(rg)
1039
0
        UA_ReaderGroup_remove(psm, rg);
1040
0
    else
1041
0
        res = UA_STATUSCODE_BADNOTFOUND;
1042
0
    unlockServer(server);
1043
0
    return res;
1044
0
}
1045
1046
UA_StatusCode
1047
UA_Server_getReaderGroupConfig(UA_Server *server, const UA_NodeId rgId,
1048
0
                               UA_ReaderGroupConfig *config) {
1049
0
    if(!server || !config)
1050
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1051
0
    lockServer(server);
1052
0
    UA_ReaderGroup *rg = UA_ReaderGroup_find(getPSM(server), rgId);
1053
0
    UA_StatusCode ret = (rg) ?
1054
0
        UA_ReaderGroupConfig_copy(&rg->config, config) : UA_STATUSCODE_BADNOTFOUND;
1055
0
    unlockServer(server);
1056
0
    return ret;
1057
0
}
1058
1059
UA_StatusCode
1060
UA_Server_getReaderGroupState(UA_Server *server, const UA_NodeId rgId,
1061
0
                              UA_PubSubState *state) {
1062
0
    if(!server || !state)
1063
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1064
0
    lockServer(server);
1065
0
    UA_StatusCode ret = UA_STATUSCODE_BADNOTFOUND;
1066
0
    UA_ReaderGroup *rg = UA_ReaderGroup_find(getPSM(server), rgId);
1067
0
    if(rg) {
1068
0
        *state = rg->head.state;
1069
0
        ret = UA_STATUSCODE_GOOD;
1070
0
    }
1071
0
    unlockServer(server);
1072
0
    return ret;
1073
0
}
1074
1075
#ifdef UA_ENABLE_PUBSUB_SKS
1076
UA_StatusCode
1077
UA_Server_setReaderGroupActivateKey(UA_Server *server,
1078
                                    const UA_NodeId readerGroupId) {
1079
    if(!server)
1080
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1081
    lockServer(server);
1082
    UA_PubSubManager *psm = getPSM(server);
1083
    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, readerGroupId);
1084
    if(!rg || !rg->keyStorage || !rg->keyStorage->currentItem) {
1085
        unlockServer(server);
1086
        return UA_STATUSCODE_BADNOTFOUND;
1087
    }
1088
    UA_StatusCode ret =
1089
        UA_PubSubKeyStorage_activateKeyToChannelContext(psm, rg->head.identifier,
1090
                                                        rg->config.securityGroupId);
1091
    unlockServer(server);
1092
    return ret;
1093
}
1094
#endif
1095
1096
UA_StatusCode
1097
0
UA_Server_enableReaderGroup(UA_Server *server, const UA_NodeId readerGroupId){
1098
0
    if(!server)
1099
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1100
0
    lockServer(server);
1101
0
    UA_PubSubManager *psm = getPSM(server);
1102
0
    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, readerGroupId);
1103
0
    UA_StatusCode ret = (rg) ?
1104
0
        UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_OPERATIONAL) :
1105
0
        UA_STATUSCODE_BADNOTFOUND;
1106
0
    unlockServer(server);
1107
0
    return ret;
1108
0
}
1109
1110
UA_StatusCode
1111
0
UA_Server_disableReaderGroup(UA_Server *server, const UA_NodeId readerGroupId){
1112
0
    if(!server)
1113
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1114
0
    lockServer(server);
1115
0
    UA_PubSubManager *psm = getPSM(server);
1116
0
    UA_ReaderGroup *rg = UA_ReaderGroup_find(psm, readerGroupId);
1117
0
    UA_StatusCode ret = (rg) ?
1118
0
        UA_ReaderGroup_setPubSubState(psm, rg, UA_PUBSUBSTATE_DISABLED) :
1119
0
        UA_STATUSCODE_BADNOTFOUND;
1120
0
    unlockServer(server);
1121
0
    return ret;
1122
0
}
1123
1124
UA_StatusCode
1125
UA_Server_setReaderGroupEncryptionKeys(UA_Server *server,
1126
                                       const UA_NodeId readerGroup,
1127
                                       UA_UInt32 securityTokenId,
1128
                                       const UA_ByteString signingKey,
1129
                                       const UA_ByteString encryptingKey,
1130
0
                                       const UA_ByteString keyNonce) {
1131
0
    if(!server)
1132
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1133
0
    lockServer(server);
1134
0
    UA_PubSubManager *psm = getPSM(server);
1135
0
    UA_ReaderGroup *rg = UA_ReaderGroup_find(getPSM(server), readerGroup);
1136
0
    UA_StatusCode res = (rg) ?
1137
0
        UA_ReaderGroup_setEncryptionKeys(psm, rg, securityTokenId, signingKey,
1138
0
                                         encryptingKey, keyNonce) : UA_STATUSCODE_BADNOTFOUND;
1139
0
    unlockServer(server);
1140
0
    return res;
1141
0
}
1142
1143
UA_StatusCode
1144
UA_Server_updateReaderGroupConfig(UA_Server *server, const UA_NodeId rgId,
1145
0
                                  const UA_ReaderGroupConfig *config) {
1146
0
    if(!server || !config)
1147
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1148
1149
0
    lockServer(server);
1150
1151
0
    UA_PubSubManager *psm = getPSM(server);
1152
0
    UA_ReaderGroup *rg = UA_ReaderGroup_find(getPSM(server), rgId);
1153
0
    if(!rg) {
1154
0
        unlockServer(server);
1155
0
        return UA_STATUSCODE_BADNOTFOUND;
1156
0
    }
1157
1158
0
    if(UA_PubSubState_isEnabled(rg->head.state)) {
1159
0
        UA_LOG_ERROR_PUBSUB(psm->logging, rg,
1160
0
                            "The ReaderGroup must be disabled to update the config");
1161
0
        unlockServer(server);
1162
0
        return UA_STATUSCODE_BADINTERNALERROR;
1163
0
    }
1164
1165
    /* Store the old config */
1166
0
    UA_ReaderGroupConfig oldConfig = rg->config;
1167
1168
    /* Deep copy of the config */
1169
0
    UA_StatusCode retval = UA_ReaderGroupConfig_copy(config, &rg->config);
1170
0
    if(retval != UA_STATUSCODE_GOOD) {
1171
0
        unlockServer(server);
1172
0
        return retval;
1173
0
    }
1174
1175
    /* Validate the connection settings */
1176
0
    retval = UA_ReaderGroup_connect(psm, rg, true);
1177
0
    if(retval != UA_STATUSCODE_GOOD) {
1178
0
        UA_LOG_ERROR_PUBSUB(psm->logging, rg,
1179
0
                            "Could not validate the connection parameters");
1180
0
        goto errout;
1181
0
    }
1182
1183
#ifdef UA_ENABLE_PUBSUB_SKS
1184
    if(!UA_String_equal(&rg->config.securityGroupId, &oldConfig.securityGroupId) ||
1185
       rg->config.securityMode != oldConfig.securityMode) {
1186
        /* Detach keystorage and reattach if needed */
1187
        if(rg->keyStorage) {
1188
            UA_PubSubKeyStorage_detachKeyStorage(psm, rg->keyStorage);
1189
            rg->keyStorage = NULL;
1190
        }
1191
        if(rg->config.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
1192
           rg->config.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
1193
            retval = readerGroupAttachSKSKeystorage(psm, rg);
1194
            if(retval != UA_STATUSCODE_GOOD) {
1195
                UA_LOG_ERROR_PUBSUB(psm->logging, rg,
1196
                                    "Attaching the SKS KeyStorage failed");
1197
                goto errout;
1198
            }
1199
        }
1200
    }
1201
#endif
1202
1203
    /* Clean up and return */
1204
0
    UA_ReaderGroupConfig_clear(&oldConfig);
1205
0
    unlockServer(server);
1206
0
    return UA_STATUSCODE_GOOD;
1207
1208
0
 errout:
1209
0
    UA_ReaderGroupConfig_clear(&rg->config);
1210
0
    rg->config = oldConfig;
1211
0
    unlockServer(server);
1212
0
    return retval;
1213
0
}
1214
1215
#endif /* UA_ENABLE_PUBSUB */