Coverage Report

Created: 2026-02-26 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/S2OPC/src/PubSub/common/sopc_pubsub_conf.c
Line
Count
Source
1
/*
2
 * Licensed to Systerel under one or more contributor license
3
 * agreements. See the NOTICE file distributed with this work
4
 * for additional information regarding copyright ownership.
5
 * Systerel licenses this file to you under the Apache
6
 * License, Version 2.0 (the "License"); you may not use this
7
 * file except in compliance with the License. You may obtain
8
 * a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
#include <errno.h>
21
#include <inttypes.h>
22
#include <stdbool.h>
23
#include <stdint.h>
24
#include <stdio.h>
25
#include <string.h>
26
27
#include "sopc_assert.h"
28
#include "sopc_helper_string.h"
29
#include "sopc_logger.h"
30
#include "sopc_mem_alloc.h"
31
#include "sopc_pubsub_conf.h"
32
33
/**
34
 * Defines a source of Data Items
35
 */
36
typedef struct SOPC_PublishedDataItemsData
37
{
38
    uint16_t length;
39
    SOPC_PublishedVariable* publishedData;
40
} SOPC_PublishedDataItemsData;
41
42
struct SOPC_PublishedVariable
43
{
44
    SOPC_NodeId* nodeId;
45
    uint32_t attributeId;
46
    char* indexRange;
47
};
48
49
/**
50
 * Defines a source of Events
51
 */
52
53
struct SOPC_PubSubConfiguration
54
{
55
    uint32_t pub_connection_length;
56
    SOPC_PubSubConnection* pub_connection;
57
58
    uint32_t sub_connection_length;
59
    SOPC_PubSubConnection* sub_connection;
60
61
    uint32_t publishedDataSet_length;
62
    SOPC_PublishedDataSet* publishedDataSet;
63
};
64
65
struct SOPC_PubSubConnection
66
{
67
    SOPC_PubSubConnection_Type type;
68
    char* name;
69
    bool enabled;
70
    SOPC_Conf_PublisherId publisherId;
71
    // Give Network and Transport Protocol as URI
72
    char* transportProfileUri;
73
    // Network interface name (Ethernet only): mandatory for Publisher
74
    char* interfaceName;
75
    // NetworkAddressDataType is string
76
    char* address;
77
    uint16_t writerGroups_length;
78
    SOPC_WriterGroup* writerGroups;
79
    uint16_t readerGroups_length;
80
    SOPC_ReaderGroup* readerGroups;
81
    // Username for MQTT protocol
82
    char* mqttUsername;
83
    // Password for MQTT protocol
84
    char* mqttPassword;
85
86
    bool acyclicPublisher;
87
88
    SOPC_PubSub_OnFatalError* onFatalError;
89
    SOPC_Pub_SignatureFailed* onPubSignatureFailed;
90
    SOPC_Sub_SignatureCheckFailed* onSubSignatureCheckFailed;
91
    // For the next version:
92
    // uint32_t connectionPropertiesLength: not used;
93
    // KeyValuePair *connectionProperties: not used;
94
    // ConnectionTransportDataType transportSettings: not used;
95
};
96
97
struct SOPC_DataSetMetaData
98
{
99
    // char* name;
100
    uint16_t fields_length;
101
    SOPC_FieldMetaData* fields;
102
103
    // configurationVersion
104
};
105
106
struct SOPC_PublishedDataSet
107
{
108
    SOPC_DataSetMetaData dataSetMetaData;
109
    // SOPC_PublishedDataSetSource dataSetSource;
110
    SOPC_PublishedDataSetSourceType dataSetSourceType;
111
112
    // For the next version:
113
    // char **dataSetFolder
114
    // KeyValuePair *extensionFields
115
};
116
117
typedef struct SOPC_UadpWriterGroup
118
{
119
    uint32_t version;
120
    SOPC_UadpNetworkMessageContentMask contentMask;
121
122
    // For the next version:
123
    // dataSetOrdering
124
    // samplingOffset
125
    // publishingOffset
126
127
} SOPC_UadpWriterGroup;
128
129
struct SOPC_WriterGroup
130
{
131
    SOPC_PubSubConnection* parent;
132
    uint16_t id;
133
    double publishingIntervalMs;
134
    int32_t publishingOffsetMs;
135
    SOPC_UadpWriterGroup messageSettings;
136
137
    uint8_t dataSetWriters_length;
138
    SOPC_DataSetWriter* dataSetWriters;
139
140
    SOPC_SecurityMode_Type securityMode;
141
142
    // Topic Specific to Mqtt
143
    char* mqttTopic;
144
145
    double keepAliveTimeMs;
146
147
    SOPC_Pubsub_MessageEncodingType messageEncoding;
148
149
    char* securityGroupId;
150
    SOPC_SecurityKeyServices* securityKeyServices;
151
    uint32_t securityKeyServices_length;
152
    SOPC_WriterGroup_Options options;
153
    // For the next version:
154
    // Priority
155
    // LocaleIds
156
    // transportSettings
157
};
158
159
struct SOPC_SecurityKeyServices
160
{
161
    char* endpointUrl;
162
    SOPC_SerializedCertificate* serverCertificate;
163
};
164
165
struct SOPC_DataSetWriter
166
{
167
    uint16_t id;
168
    // dataSetName in structure defined in Spec 1.4
169
    SOPC_PublishedDataSet*
170
        dataSet; /* IMPORTANT NOTE: memory management of field not managed here (see global config struct)*/
171
    SOPC_DataSetWriter_Options options;
172
    // For the next version:
173
    // name
174
    // enabled
175
    // dataSetFieldContentMask
176
    // keyFrameCount
177
    // dataSetWriterProperties
178
    // transportSettings
179
    // messageSettings
180
};
181
182
struct SOPC_ReaderGroup
183
{
184
    SOPC_SecurityMode_Type securityMode;
185
186
    SOPC_Conf_PublisherId publisherId;
187
188
    char* securityGroupId;
189
190
    SOPC_SecurityKeyServices* securityKeyServices;
191
    uint32_t securityKeyServices_length;
192
193
    uint8_t dataSetReaders_length;
194
    SOPC_DataSetReader* dataSetReaders;
195
    uint16_t groupId;
196
    uint32_t groupVersion;
197
198
    // Topic Specific to Mqtt
199
    char* mqttTopic;
200
};
201
202
struct SOPC_DataSetReader
203
{
204
    struct SOPC_ReaderGroup* group;
205
    uint16_t dataSetWriterId;
206
    SOPC_DataSetMetaData metaData;
207
    SOPC_SubscribedDataSetType targetType;
208
    double messageReceiveTimeout; /* ms */
209
210
    // These fields below are defined in Spec but not used
211
    // DataSetFieldContentMask
212
213
    // SecurityMode
214
    // SecurityGroupId
215
    // SecurityKeyServices
216
    // DataSetReaderProperties
217
    // transportSettings
218
    // messageSettings
219
};
220
221
struct SOPC_FieldTarget
222
{
223
    // numeric range format
224
    char* receiverIndexRange;
225
    SOPC_NodeId* nodeId;
226
    uint32_t attributeId;
227
    // numeric range format
228
    char* writeIndexRange;
229
230
    // override value is not managed
231
    // overrideValueHandling
232
    // overrideValue
233
};
234
235
struct SOPC_FieldMetaData
236
{
237
    // char* name;
238
    SOPC_BuiltinId builtinType;
239
    SOPC_PubSub_ArrayDimension arrDimension;
240
241
    // other field are not used
242
    // only one element. used for subscriber
243
    SOPC_FieldTarget* targetVariable;
244
    // only one element. used for publisher
245
    SOPC_PublishedVariable* publishedVariable;
246
};
247
248
static bool SOPC_PubSubConfiguration_Allocate_PubSubConnection_Array(SOPC_PubSubConfiguration* configuration,
249
                                                                     uint32_t nb,
250
                                                                     SOPC_PubSubConnection** arrayPtr,
251
                                                                     uint32_t* lengthPtr,
252
                                                                     SOPC_PubSubConnection_Type type);
253
254
static char* SOPC_PubSub_String_Copy(const char* src);
255
256
static void SOPC_PubSubConnection_Clear(SOPC_PubSubConnection* connection);
257
258
static void SOPC_PublishedDataSet_Clear(SOPC_PublishedDataSet* dataset);
259
260
static void SOPC_WriterGroup_Clear(SOPC_WriterGroup* group);
261
262
static void SOPC_SecurityKeyServices_Clear(SOPC_SecurityKeyServices* sks);
263
264
static void SOPC_ReaderGroup_Clear(SOPC_ReaderGroup* group);
265
266
static void SOPC_DataSetMetaData_Clear(SOPC_DataSetMetaData* metaData);
267
268
static void SOPC_FieldTarget_Clear(SOPC_FieldTarget* target);
269
270
static void SOPC_PublishedVariable_Clear(SOPC_PublishedVariable* variable);
271
272
static void SOPC_Conf_PublisherId_Clear(SOPC_Conf_PublisherId* pubId);
273
274
SOPC_PubSubConfiguration* SOPC_PubSubConfiguration_Create(void)
275
2
{
276
    // free in SOPC_PubSubConfiguration_Delete
277
2
    SOPC_PubSubConfiguration* configuration = SOPC_Calloc(1, sizeof(SOPC_PubSubConfiguration));
278
2
    if (NULL == configuration)
279
0
    {
280
0
        return NULL;
281
0
    }
282
2
    return configuration;
283
2
}
284
285
void SOPC_PubSubConfiguration_Delete(SOPC_PubSubConfiguration* configuration)
286
0
{
287
0
    if (NULL == configuration)
288
0
    {
289
0
        return;
290
0
    }
291
0
    for (uint32_t i = 0; i < configuration->pub_connection_length; i++)
292
0
    {
293
0
        SOPC_PubSubConnection_Clear(&(configuration->pub_connection[i]));
294
0
    }
295
0
    SOPC_Free(configuration->pub_connection);
296
0
    for (uint32_t i = 0; i < configuration->sub_connection_length; i++)
297
0
    {
298
0
        SOPC_PubSubConnection_Clear(&(configuration->sub_connection[i]));
299
0
    }
300
0
    SOPC_Free(configuration->sub_connection);
301
0
    for (uint32_t i = 0; i < configuration->publishedDataSet_length; i++)
302
0
    {
303
0
        SOPC_PublishedDataSet_Clear(&(configuration->publishedDataSet[i]));
304
0
    }
305
0
    SOPC_Free(configuration->publishedDataSet);
306
0
    SOPC_Free(configuration);
307
0
}
308
309
static bool SOPC_PubSubConfiguration_Allocate_PubSubConnection_Array(SOPC_PubSubConfiguration* configuration,
310
                                                                     uint32_t nb,
311
                                                                     SOPC_PubSubConnection** arrayPtr,
312
                                                                     uint32_t* lengthPtr,
313
                                                                     SOPC_PubSubConnection_Type type)
314
2
{
315
2
    SOPC_ASSERT(NULL != configuration && NULL != arrayPtr && NULL != lengthPtr);
316
    // free in SOPC_PubSubConfiguration_Delete
317
2
    *arrayPtr = SOPC_Calloc(nb, sizeof(SOPC_PubSubConnection));
318
2
    if (NULL == *arrayPtr)
319
0
    {
320
0
        return false;
321
0
    }
322
2
    *lengthPtr = nb;
323
4
    for (uint32_t i = 0; i < nb; i++)
324
2
    {
325
2
        (*arrayPtr)[i].type = type;
326
2
        (*arrayPtr)[i].publisherId.type = SOPC_Null_PublisherId;
327
2
    }
328
329
2
    return true;
330
2
}
331
332
bool SOPC_PubSubConfiguration_Allocate_PubConnection_Array(SOPC_PubSubConfiguration* configuration, uint32_t nb)
333
0
{
334
0
    return SOPC_PubSubConfiguration_Allocate_PubSubConnection_Array(configuration, nb, &(configuration->pub_connection),
335
0
                                                                    &(configuration->pub_connection_length),
336
0
                                                                    SOPC_PubSubConnection_Pub);
337
0
}
338
339
uint32_t SOPC_PubSubConfiguration_Nb_PubConnection(const SOPC_PubSubConfiguration* configuration)
340
0
{
341
0
    SOPC_ASSERT(NULL != configuration);
342
0
    return configuration->pub_connection_length;
343
0
}
344
345
SOPC_PubSubConnection* SOPC_PubSubConfiguration_Get_PubConnection_At(const SOPC_PubSubConfiguration* configuration,
346
                                                                     uint32_t index)
347
0
{
348
0
    SOPC_ASSERT(NULL != configuration && index < configuration->pub_connection_length);
349
0
    return &(configuration->pub_connection[index]);
350
0
}
351
352
bool SOPC_PubSubConfiguration_Allocate_SubConnection_Array(SOPC_PubSubConfiguration* configuration, uint32_t nb)
353
2
{
354
2
    return SOPC_PubSubConfiguration_Allocate_PubSubConnection_Array(configuration, nb, &(configuration->sub_connection),
355
2
                                                                    &(configuration->sub_connection_length),
356
2
                                                                    SOPC_PubSubConnection_Sub);
357
2
}
358
359
uint32_t SOPC_PubSubConfiguration_Nb_SubConnection(const SOPC_PubSubConfiguration* configuration)
360
0
{
361
0
    SOPC_ASSERT(NULL != configuration);
362
0
    return configuration->sub_connection_length;
363
0
}
364
365
SOPC_PubSubConnection* SOPC_PubSubConfiguration_Get_SubConnection_At(const SOPC_PubSubConfiguration* configuration,
366
                                                                     uint32_t index)
367
2
{
368
2
    SOPC_ASSERT(NULL != configuration && index < configuration->sub_connection_length);
369
2
    return &(configuration->sub_connection[index]);
370
2
}
371
372
bool SOPC_PubSubConfiguration_Allocate_PublishedDataSet_Array(SOPC_PubSubConfiguration* configuration, uint32_t nb)
373
0
{
374
0
    SOPC_ASSERT(NULL != configuration);
375
    // free in SOPC_PubSubConfiguration_Delete
376
0
    configuration->publishedDataSet = SOPC_Calloc(nb, sizeof(SOPC_PublishedDataSet));
377
0
    if (NULL == configuration->publishedDataSet)
378
0
    {
379
0
        return false;
380
0
    }
381
0
    configuration->publishedDataSet_length = nb;
382
0
    return true;
383
0
}
384
385
uint32_t SOPC_PubSubConfiguration_Nb_PublishedDataSet(const SOPC_PubSubConfiguration* configuration)
386
0
{
387
0
    SOPC_ASSERT(NULL != configuration);
388
0
    return configuration->publishedDataSet_length;
389
0
}
390
391
SOPC_PublishedDataSet* SOPC_PubSubConfiguration_Get_PublishedDataSet_At(const SOPC_PubSubConfiguration* configuration,
392
                                                                        uint16_t index)
393
0
{
394
0
    SOPC_ASSERT(NULL != configuration && index < configuration->publishedDataSet_length);
395
0
    return &(configuration->publishedDataSet[index]);
396
0
}
397
398
void SOPC_PubSubConnection_Set_AcyclicPublisher(SOPC_PubSubConnection* connection, bool acyclicPublisher)
399
0
{
400
0
    SOPC_ASSERT(NULL != connection);
401
0
    connection->acyclicPublisher = acyclicPublisher;
402
0
}
403
404
bool SOPC_PubSubConnection_Get_AcyclicPublisher(const SOPC_PubSubConnection* connection)
405
0
{
406
0
    SOPC_ASSERT(NULL != connection);
407
0
    return connection->acyclicPublisher;
408
0
}
409
410
static void SOPC_PubSubConnection_Clear(SOPC_PubSubConnection* connection)
411
0
{
412
0
    if (NULL != connection)
413
0
    {
414
0
        SOPC_Free(connection->name);
415
0
        SOPC_Conf_PublisherId_Clear(&connection->publisherId);
416
0
        SOPC_Free(connection->address);
417
0
        SOPC_Free(connection->interfaceName);
418
0
        SOPC_Free(connection->mqttUsername);
419
0
        SOPC_Free(connection->mqttPassword);
420
0
        SOPC_Free(connection->transportProfileUri);
421
0
        SOPC_String_Clear(&connection->publisherId.data.string);
422
0
        for (int i = 0; i < connection->writerGroups_length; i++)
423
0
        {
424
0
            SOPC_WriterGroup_Clear(&(connection->writerGroups[i]));
425
0
        }
426
0
        SOPC_Free(connection->writerGroups);
427
0
        for (int i = 0; i < connection->readerGroups_length; i++)
428
0
        {
429
0
            SOPC_ReaderGroup_Clear(&(connection->readerGroups[i]));
430
0
        }
431
0
        SOPC_Free(connection->readerGroups);
432
0
    }
433
0
}
434
435
const char* SOPC_PubSubConnection_Get_Name(const SOPC_PubSubConnection* connection)
436
0
{
437
0
    return connection->name;
438
0
}
439
440
bool SOPC_PubSubConnection_Set_Name(SOPC_PubSubConnection* connection, const char* name)
441
0
{
442
0
    SOPC_ASSERT(NULL != connection);
443
    // free in SOPC_PubSubConnection_Clear
444
0
    connection->name = SOPC_PubSub_String_Copy(name);
445
0
    return (NULL != connection->name);
446
0
}
447
448
bool SOPC_PubSubConnection_Is_Enabled(const SOPC_PubSubConnection* connection)
449
0
{
450
0
    SOPC_ASSERT(NULL != connection);
451
0
    return connection->enabled;
452
0
}
453
454
void SOPC_PubSubConnection_Set_Enabled(SOPC_PubSubConnection* connection, bool enabled)
455
0
{
456
0
    SOPC_ASSERT(NULL != connection);
457
0
    connection->enabled = enabled;
458
0
}
459
460
void SOPC_PubSubConfiguration_Set_FatalError_Callback(SOPC_PubSubConnection* connection,
461
                                                      SOPC_PubSub_OnFatalError* callback)
462
0
{
463
0
    SOPC_ASSERT(NULL != connection);
464
0
    connection->onFatalError = callback;
465
0
}
466
467
SOPC_PubSub_OnFatalError* SOPC_PubSubConfiguration_Get_FatalError_Callback(SOPC_PubSubConnection* connection)
468
0
{
469
0
    SOPC_ASSERT(NULL != connection);
470
0
    return connection->onFatalError;
471
0
}
472
473
void SOPC_PubSubConfiguration_Set_PubSignatureFailed_Callback(SOPC_PubSubConnection* connection,
474
                                                              SOPC_Pub_SignatureFailed* callback)
475
0
{
476
0
    if (connection != NULL)
477
0
    {
478
0
        connection->onPubSignatureFailed = callback;
479
0
    }
480
0
}
481
482
void SOPC_PubSubConfiguration_Set_SubSignatureCheckFailed_Callback(SOPC_PubSubConnection* connection,
483
                                                                   SOPC_Sub_SignatureCheckFailed* callback)
484
0
{
485
0
    if (connection != NULL)
486
0
    {
487
0
        connection->onSubSignatureCheckFailed = callback;
488
0
    }
489
0
}
490
491
SOPC_Pub_SignatureFailed* SOPC_PubSubConfiguration_Get_PubSignatureFailed_Callback(
492
    const SOPC_PubSubConnection* connection)
493
0
{
494
0
    if (connection != NULL)
495
0
    {
496
0
        return connection->onPubSignatureFailed;
497
0
    }
498
0
    return NULL;
499
0
}
500
501
SOPC_Sub_SignatureCheckFailed* SOPC_PubSubConfiguration_Get_SubSignatureCheckFailed_Callback(
502
    const SOPC_PubSubConnection* connection)
503
0
{
504
0
    if (connection != NULL)
505
0
    {
506
0
        return connection->onSubSignatureCheckFailed;
507
0
    }
508
0
    return NULL;
509
0
}
510
511
// PublisherId
512
513
static void SOPC_Conf_PublisherId_Clear(SOPC_Conf_PublisherId* pubId)
514
0
{
515
0
    if (NULL != pubId && SOPC_String_PublisherId == pubId->type)
516
0
    {
517
0
        SOPC_String_Clear(&pubId->data.string);
518
0
    }
519
0
}
520
521
const SOPC_Conf_PublisherId* SOPC_PubSubConnection_Get_PublisherId(const SOPC_PubSubConnection* connection)
522
0
{
523
0
    SOPC_ASSERT(NULL != connection);
524
0
    return &(connection->publisherId);
525
0
}
526
527
void SOPC_PubSubConnection_Set_PublisherId_UInteger(SOPC_PubSubConnection* connection, uint64_t id)
528
0
{
529
0
    SOPC_ASSERT(NULL != connection && SOPC_PubSubConnection_Pub == connection->type);
530
0
    connection->publisherId.type = SOPC_UInteger_PublisherId;
531
0
    connection->publisherId.data.uint = id;
532
0
}
533
534
bool SOPC_PubSubConnection_Set_PublisherId_String(SOPC_PubSubConnection* connection, const SOPC_String* id)
535
0
{
536
0
    SOPC_ASSERT(NULL != connection && NULL != id && SOPC_PubSubConnection_Pub == connection->type);
537
0
    connection->publisherId.type = SOPC_String_PublisherId;
538
0
    SOPC_String_Initialize(&connection->publisherId.data.string);
539
0
    SOPC_ReturnStatus status = SOPC_String_Copy(&connection->publisherId.data.string, id);
540
0
    return (SOPC_STATUS_OK == status);
541
0
}
542
543
const char* SOPC_PubSubConnection_Get_TransportProfileUri(const SOPC_PubSubConnection* connection)
544
0
{
545
0
    SOPC_ASSERT(NULL != connection);
546
0
    return connection->transportProfileUri;
547
0
}
548
549
bool SOPC_PubSubConnection_Set_TransportProfileUri(SOPC_PubSubConnection* connection, const char* uri)
550
0
{
551
0
    SOPC_ASSERT(NULL != connection);
552
    // free in SOPC_PubSubConnection_Clear
553
0
    connection->transportProfileUri = SOPC_PubSub_String_Copy(uri);
554
0
    return (NULL != connection->transportProfileUri);
555
0
}
556
557
const char* SOPC_PubSubConnection_Get_Address(const SOPC_PubSubConnection* connection)
558
0
{
559
0
    SOPC_ASSERT(NULL != connection);
560
0
    return connection->address;
561
0
}
562
563
bool SOPC_PubSubConnection_Set_Address(SOPC_PubSubConnection* connection, const char* address)
564
0
{
565
0
    SOPC_ASSERT(NULL != connection);
566
    // free in SOPC_PubSubConnection_Clear
567
0
    connection->address = SOPC_PubSub_String_Copy(address);
568
0
    return (NULL != connection->address);
569
0
}
570
571
const char* SOPC_PubSubConnection_Get_InterfaceName(const SOPC_PubSubConnection* connection)
572
0
{
573
0
    SOPC_ASSERT(NULL != connection);
574
0
    return connection->interfaceName;
575
0
}
576
577
bool SOPC_PubSubConnection_Set_InterfaceName(SOPC_PubSubConnection* connection, const char* interfaceName)
578
0
{
579
0
    SOPC_ASSERT(NULL != connection);
580
    // free in SOPC_PubSubConnection_Clear
581
0
    connection->interfaceName = SOPC_PubSub_String_Copy(interfaceName);
582
0
    return (NULL != connection->interfaceName);
583
0
}
584
585
const char* SOPC_PubSubConnection_Get_MqttUsername(const SOPC_PubSubConnection* connection)
586
0
{
587
0
    SOPC_ASSERT(NULL != connection);
588
0
    return connection->mqttUsername;
589
0
}
590
591
bool SOPC_PubSubConnection_Set_MqttUsername(SOPC_PubSubConnection* connection, const char* username)
592
0
{
593
0
    SOPC_ASSERT(NULL != username);
594
0
    connection->mqttUsername = SOPC_PubSub_String_Copy(username);
595
0
    return (NULL != connection->mqttUsername);
596
0
}
597
598
const char* SOPC_PubSubConnection_Get_MqttPassword(const SOPC_PubSubConnection* connection)
599
0
{
600
0
    SOPC_ASSERT(NULL != connection);
601
0
    return connection->mqttPassword;
602
0
}
603
604
bool SOPC_PubSubConnection_Set_MqttPassword(SOPC_PubSubConnection* connection, const char* password)
605
0
{
606
0
    SOPC_ASSERT(NULL != password);
607
0
    connection->mqttPassword = SOPC_PubSub_String_Copy(password);
608
0
    return (NULL != connection->mqttPassword);
609
0
}
610
611
bool SOPC_PubSubConnection_Allocate_WriterGroup_Array(SOPC_PubSubConnection* connection, uint16_t nb)
612
0
{
613
0
    SOPC_ASSERT(NULL != connection && SOPC_PubSubConnection_Pub == connection->type);
614
    // free in SOPC_PubSubConnection_Clear
615
0
    connection->writerGroups = SOPC_Calloc(nb, sizeof(SOPC_WriterGroup));
616
0
    if (NULL == connection->writerGroups)
617
0
    {
618
0
        return false;
619
0
    }
620
0
    connection->writerGroups_length = nb;
621
0
    for (int i = 0; i < nb; i++)
622
0
    {
623
0
        connection->writerGroups[i].parent = connection;
624
        // As publishingOffsetMs is optional, it shall be initialized here
625
0
        connection->writerGroups[i].publishingOffsetMs = -1;
626
0
    }
627
0
    return true;
628
0
}
629
630
uint16_t SOPC_PubSubConnection_Nb_WriterGroup(const SOPC_PubSubConnection* connection)
631
0
{
632
0
    SOPC_ASSERT(NULL != connection);
633
0
    return connection->writerGroups_length;
634
0
}
635
636
SOPC_WriterGroup* SOPC_PubSubConnection_Get_WriterGroup_At(const SOPC_PubSubConnection* connection, uint16_t index)
637
0
{
638
0
    SOPC_ASSERT(NULL != connection && index < connection->writerGroups_length);
639
0
    return &connection->writerGroups[index];
640
0
}
641
642
bool SOPC_PubSubConnection_Allocate_ReaderGroup_Array(SOPC_PubSubConnection* connection, uint16_t nb)
643
2
{
644
2
    SOPC_ASSERT(NULL != connection && SOPC_PubSubConnection_Sub == connection->type);
645
    // free in SOPC_PubSubConnection_Clear
646
2
    connection->readerGroups = SOPC_Calloc(nb, sizeof(SOPC_ReaderGroup));
647
2
    if (NULL == connection->readerGroups)
648
0
    {
649
0
        return false;
650
0
    }
651
2
    connection->readerGroups_length = nb;
652
6
    for (int i = 0; i < nb; i++)
653
4
    {
654
4
        memset(&connection->readerGroups[i], 0, sizeof(SOPC_ReaderGroup));
655
4
        connection->readerGroups[i].publisherId.type = SOPC_Null_PublisherId;
656
4
    }
657
2
    return true;
658
2
}
659
660
uint16_t SOPC_PubSubConnection_Nb_ReaderGroup(const SOPC_PubSubConnection* connection)
661
7.26k
{
662
7.26k
    SOPC_ASSERT(NULL != connection);
663
7.26k
    return connection->readerGroups_length;
664
7.26k
}
665
666
SOPC_ReaderGroup* SOPC_PubSubConnection_Get_ReaderGroup_At(const SOPC_PubSubConnection* connection, uint16_t index)
667
7.61k
{
668
7.61k
    SOPC_ASSERT(NULL != connection && index < connection->readerGroups_length);
669
7.61k
    return &connection->readerGroups[index];
670
7.61k
}
671
672
/** Reader Group **/
673
674
SOPC_SecurityMode_Type SOPC_ReaderGroup_Get_SecurityMode(const SOPC_ReaderGroup* group)
675
0
{
676
0
    SOPC_ASSERT(NULL != group);
677
0
    return group->securityMode;
678
0
}
679
680
void SOPC_ReaderGroup_Set_SecurityMode(SOPC_ReaderGroup* group, SOPC_SecurityMode_Type mode)
681
4
{
682
4
    SOPC_ASSERT(NULL != group);
683
4
    group->securityMode = mode;
684
4
}
685
686
const char* SOPC_ReaderGroup_Get_SecurityGroupId(const SOPC_ReaderGroup* group)
687
0
{
688
0
    SOPC_ASSERT(NULL != group);
689
0
    return group->securityGroupId;
690
0
}
691
692
void SOPC_ReaderGroup_Set_SecurityGroupId(SOPC_ReaderGroup* group, const char* securityGroupId)
693
0
{
694
0
    SOPC_ASSERT(NULL != group);
695
0
    if (NULL == securityGroupId)
696
0
    {
697
0
        group->securityGroupId = NULL;
698
0
    }
699
0
    else
700
0
    {
701
0
        group->securityGroupId = SOPC_PubSub_String_Copy(securityGroupId);
702
0
        SOPC_ASSERT(NULL != group->securityGroupId);
703
0
    }
704
0
}
705
706
bool SOPC_ReaderGroup_Allocate_SecurityKeyServices_Array(SOPC_ReaderGroup* group, uint32_t nb)
707
0
{
708
0
    SOPC_ASSERT(NULL != group);
709
    // free in SOPC_ReaderGroup_Clear
710
0
    group->securityKeyServices = SOPC_Calloc(nb, sizeof(SOPC_SecurityKeyServices));
711
0
    if (NULL == group->securityKeyServices)
712
0
    {
713
0
        return false;
714
0
    }
715
0
    group->securityKeyServices_length = nb;
716
0
    return true;
717
0
}
718
719
uint32_t SOPC_ReaderGroup_Nb_SecurityKeyServices(const SOPC_ReaderGroup* group)
720
0
{
721
0
    SOPC_ASSERT(NULL != group);
722
0
    return group->securityKeyServices_length;
723
0
}
724
725
SOPC_SecurityKeyServices* SOPC_ReaderGroup_Get_SecurityKeyServices_At(const SOPC_ReaderGroup* group, uint32_t index)
726
0
{
727
0
    SOPC_ASSERT(NULL != group);
728
0
    SOPC_ASSERT(index < group->securityKeyServices_length);
729
0
    SOPC_ASSERT(NULL != group->securityKeyServices);
730
0
    return &group->securityKeyServices[index];
731
0
}
732
733
bool SOPC_ReaderGroup_Allocate_DataSetReader_Array(SOPC_ReaderGroup* group, uint8_t nb)
734
4
{
735
4
    SOPC_ASSERT(NULL != group);
736
    // free in SOPC_ReaderGroup_Clear
737
4
    group->dataSetReaders = SOPC_Calloc(nb, sizeof(SOPC_DataSetReader));
738
4
    if (NULL == group->dataSetReaders)
739
0
    {
740
0
        return false;
741
0
    }
742
8
    for (size_t i = 0; i < nb; i++)
743
4
    {
744
4
        group->dataSetReaders[i].group = group;
745
4
    }
746
4
    group->dataSetReaders_length = nb;
747
4
    return true;
748
4
}
749
750
uint8_t SOPC_ReaderGroup_Nb_DataSetReader(const SOPC_ReaderGroup* group)
751
10.6k
{
752
10.6k
    SOPC_ASSERT(NULL != group);
753
10.6k
    return group->dataSetReaders_length;
754
10.6k
}
755
756
SOPC_DataSetReader* SOPC_ReaderGroup_Get_DataSetReader_At(const SOPC_ReaderGroup* group, uint8_t index)
757
10.6k
{
758
10.6k
    SOPC_ASSERT(NULL != group && index < group->dataSetReaders_length);
759
10.6k
    return &group->dataSetReaders[index];
760
10.6k
}
761
762
uint16_t SOPC_ReaderGroup_Get_GroupId(const SOPC_ReaderGroup* group)
763
7.13k
{
764
7.13k
    SOPC_ASSERT(NULL != group);
765
7.13k
    return group->groupId;
766
7.13k
}
767
768
void SOPC_ReaderGroup_Set_GroupId(SOPC_ReaderGroup* group, uint16_t id)
769
4
{
770
4
    SOPC_ASSERT(NULL != group);
771
4
    group->groupId = id;
772
4
}
773
774
uint32_t SOPC_ReaderGroup_Get_GroupVersion(const SOPC_ReaderGroup* group)
775
95
{
776
95
    SOPC_ASSERT(NULL != group);
777
95
    return group->groupVersion;
778
95
}
779
780
void SOPC_ReaderGroup_Set_GroupVersion(SOPC_ReaderGroup* group, uint32_t version)
781
4
{
782
4
    SOPC_ASSERT(NULL != group);
783
4
    group->groupVersion = version;
784
4
}
785
786
const SOPC_Conf_PublisherId* SOPC_ReaderGroup_Get_PublisherId(const SOPC_ReaderGroup* group)
787
549
{
788
549
    SOPC_ASSERT(NULL != group);
789
549
    return &(group->publisherId);
790
549
}
791
792
void SOPC_ReaderGroup_Set_PublisherId_UInteger(SOPC_ReaderGroup* group, uint64_t id)
793
2
{
794
2
    SOPC_ASSERT(NULL != group);
795
2
    group->publisherId.type = SOPC_UInteger_PublisherId;
796
2
    group->publisherId.data.uint = id;
797
2
}
798
799
bool SOPC_ReaderGroup_Set_PublisherId_String(SOPC_ReaderGroup* group, const SOPC_String* id)
800
0
{
801
0
    SOPC_ASSERT(NULL != group && NULL != id);
802
0
    group->publisherId.type = SOPC_String_PublisherId;
803
0
    SOPC_String_Initialize(&group->publisherId.data.string);
804
0
    SOPC_ReturnStatus status = SOPC_String_Copy(&group->publisherId.data.string, id);
805
0
    return (SOPC_STATUS_OK == status);
806
0
}
807
808
/** DataSetReader **/
809
810
static void SOPC_DataSetMetaData_Clear(SOPC_DataSetMetaData* metaData)
811
0
{
812
0
    for (int i = 0; i < metaData->fields_length; i++)
813
0
    {
814
0
        SOPC_FieldTarget_Clear(metaData->fields[i].targetVariable);
815
0
        SOPC_Free(metaData->fields[i].targetVariable);
816
0
        SOPC_PublishedVariable_Clear(metaData->fields[i].publishedVariable);
817
0
        SOPC_Free(metaData->fields[i].publishedVariable);
818
0
        SOPC_Free(metaData->fields[i].arrDimension.arrayDimensions);
819
0
    }
820
0
    metaData->fields_length = 0;
821
0
    SOPC_Free(metaData->fields);
822
0
    metaData->fields = NULL;
823
0
}
824
825
SOPC_ReaderGroup* SOPC_DataSetReader_Get_ReaderGroup(const SOPC_DataSetReader* reader)
826
0
{
827
0
    SOPC_ASSERT(NULL != reader);
828
0
    return reader->group;
829
0
}
830
831
uint16_t SOPC_DataSetReader_Get_DataSetWriterId(const SOPC_DataSetReader* reader)
832
10.6k
{
833
10.6k
    SOPC_ASSERT(NULL != reader);
834
10.6k
    return reader->dataSetWriterId;
835
10.6k
}
836
837
void SOPC_DataSetReader_Set_DataSetWriterId(SOPC_DataSetReader* reader, uint16_t id)
838
4
{
839
4
    SOPC_ASSERT(NULL != reader && id > 0);
840
841
4
    reader->dataSetWriterId = id;
842
4
}
843
844
const char* SOPC_ReaderGroup_Get_MqttTopic(const SOPC_ReaderGroup* reader)
845
0
{
846
0
    SOPC_ASSERT(NULL != reader);
847
0
    return reader->mqttTopic;
848
0
}
849
850
void SOPC_ReaderGroup_Set_MqttTopic(SOPC_ReaderGroup* reader, const char* topic)
851
0
{
852
0
    SOPC_ASSERT(NULL != reader);
853
0
    if (NULL != reader->mqttTopic)
854
0
    {
855
0
        SOPC_Free(reader->mqttTopic);
856
0
    }
857
0
    if (NULL == topic)
858
0
    {
859
0
        reader->mqttTopic = NULL;
860
0
    }
861
0
    else
862
0
    {
863
0
        reader->mqttTopic = SOPC_PubSub_String_Copy(topic);
864
0
        SOPC_ASSERT(NULL != reader->mqttTopic);
865
0
    }
866
0
}
867
868
char* SOPC_Allocate_MQTT_DefaultTopic(const SOPC_Conf_PublisherId* publisherId, uint16_t groupId)
869
0
{
870
0
    SOPC_ASSERT(NULL != publisherId);
871
0
    char* defaultTopic = NULL;
872
0
    int res = 0;
873
0
    static const size_t length_max_default_topic =
874
0
        SOPC_MAX_LENGTH_UINT64_TO_STRING + 1 + SOPC_MAX_LENGTH_UINT16_TO_STRING;
875
876
0
    if (SOPC_UInteger_PublisherId == publisherId->type)
877
0
    {
878
0
        defaultTopic =
879
0
            SOPC_Calloc(length_max_default_topic + 1, sizeof(char)); // + 1 to store the terminating null character
880
0
        SOPC_ASSERT(NULL != defaultTopic);
881
0
        res = snprintf(defaultTopic, length_max_default_topic + 1, "%" PRIu64 ".%" PRIu16, publisherId->data.uint,
882
0
                       groupId);
883
0
    }
884
0
    SOPC_ASSERT(SOPC_String_PublisherId != publisherId->type); // Not handled in current version
885
0
    SOPC_ASSERT(res > 0 && res < (int) length_max_default_topic + 1);
886
0
    return defaultTopic;
887
0
}
888
889
char* SOPC_Conf_PublisherIdToString(const SOPC_Conf_PublisherId* publisherId)
890
0
{
891
0
    if (NULL == publisherId)
892
0
    {
893
0
        return NULL;
894
0
    }
895
0
    char* result = NULL;
896
0
    int res = 0;
897
898
0
    switch (publisherId->type)
899
0
    {
900
0
    case SOPC_Null_PublisherId:
901
0
        result = SOPC_strdup("null");
902
0
        break;
903
0
    case SOPC_UInteger_PublisherId:
904
0
        result = SOPC_Calloc(SOPC_MAX_LENGTH_UINT64_TO_STRING + 1, sizeof(char));
905
0
        if (NULL != result)
906
0
        {
907
0
            res = snprintf(result, SOPC_MAX_LENGTH_UINT64_TO_STRING + 1, "%" PRIu64, publisherId->data.uint);
908
0
            SOPC_ASSERT(res > 0 && res < (int) SOPC_MAX_LENGTH_UINT64_TO_STRING + 1);
909
0
        }
910
0
        break;
911
912
0
    case SOPC_String_PublisherId:
913
0
        result = SOPC_String_GetCString(&publisherId->data.string);
914
0
        break;
915
916
0
    default:
917
        // Unknown type, return NULL
918
0
        break;
919
0
    }
920
921
0
    return result;
922
0
}
923
924
bool SOPC_DataSetReader_Allocate_FieldMetaData_Array(SOPC_DataSetReader* reader,
925
                                                     SOPC_SubscribedDataSetType type,
926
                                                     uint16_t nb)
927
4
{
928
4
    SOPC_ASSERT(NULL != reader);
929
4
    reader->targetType = type;
930
    // free in SOPC_DataSetMetaData_Clear
931
4
    reader->metaData.fields = SOPC_Calloc(nb, sizeof(SOPC_FieldMetaData));
932
4
    if (NULL == reader->metaData.fields)
933
0
    {
934
0
        return false;
935
0
    }
936
4
    reader->metaData.fields_length = nb;
937
22
    for (int i = 0; i < nb; i++)
938
18
    {
939
        // free in SOPC_DataSetMetaData_Clear
940
18
        SOPC_FieldTarget* target = SOPC_Calloc(1, sizeof(SOPC_FieldTarget));
941
18
        if (NULL == target)
942
0
        {
943
0
            SOPC_DataSetMetaData_Clear(&(reader->metaData));
944
0
            return false;
945
0
        }
946
18
        reader->metaData.fields[i].targetVariable = target;
947
18
    }
948
4
    return true;
949
4
}
950
951
uint16_t SOPC_DataSetReader_Nb_FieldMetaData(const SOPC_DataSetReader* reader)
952
434
{
953
434
    SOPC_ASSERT(NULL != reader);
954
434
    return reader->metaData.fields_length;
955
434
}
956
957
SOPC_FieldMetaData* SOPC_DataSetReader_Get_FieldMetaData_At(const SOPC_DataSetReader* reader, uint16_t index)
958
732
{
959
732
    SOPC_ASSERT(NULL != reader);
960
732
    SOPC_ASSERT(index < reader->metaData.fields_length);
961
732
    return &(reader->metaData.fields[index]);
962
732
}
963
964
SOPC_SubscribedDataSetType SOPC_DataSetReader_Get_DataSet_TargetType(const SOPC_DataSetReader* reader)
965
0
{
966
0
    SOPC_ASSERT(NULL != reader);
967
0
    return reader->targetType;
968
0
}
969
970
double SOPC_DataSetReader_Get_ReceiveTimeout(const SOPC_DataSetReader* reader)
971
0
{
972
0
    SOPC_ASSERT(NULL != reader);
973
0
    return reader->messageReceiveTimeout;
974
0
}
975
976
void SOPC_DataSetReader_Set_ReceiveTimeout(SOPC_DataSetReader* reader, double timeout_ms)
977
0
{
978
0
    SOPC_ASSERT(NULL != reader);
979
0
    reader->messageReceiveTimeout = timeout_ms;
980
0
}
981
982
/** SOPC_FieldTarget **/
983
984
const char* SOPC_FieldTarget_Get_SourceIndexRange(const SOPC_FieldTarget* target)
985
0
{
986
0
    return target->receiverIndexRange;
987
0
}
988
989
bool SOPC_FieldTarget_Set_SourceIndexRange(SOPC_FieldTarget* target, const char* sourceIndexRange)
990
0
{
991
0
    SOPC_ASSERT(NULL != target && NULL != sourceIndexRange);
992
    // free in SOPC_FieldTarget_Clear
993
0
    target->receiverIndexRange = SOPC_PubSub_String_Copy(sourceIndexRange);
994
0
    return (NULL != target->receiverIndexRange);
995
0
}
996
997
const SOPC_NodeId* SOPC_FieldTarget_Get_NodeId(const SOPC_FieldTarget* target)
998
217
{
999
217
    SOPC_ASSERT(NULL != target);
1000
217
    return target->nodeId;
1001
217
}
1002
1003
void SOPC_FieldTarget_Set_NodeId(SOPC_FieldTarget* target, SOPC_NodeId* nodeId)
1004
0
{
1005
0
    SOPC_ASSERT(NULL != target && NULL != nodeId);
1006
    // free in SOPC_FieldTarget_Clear
1007
0
    target->nodeId = nodeId;
1008
0
}
1009
1010
uint32_t SOPC_FieldTarget_Get_AttributeId(const SOPC_FieldTarget* target)
1011
0
{
1012
0
    SOPC_ASSERT(NULL != target);
1013
0
    return target->attributeId;
1014
0
}
1015
1016
void SOPC_FieldTarget_Set_AttributeId(SOPC_FieldTarget* target, uint32_t attributeId)
1017
0
{
1018
0
    SOPC_ASSERT(NULL != target);
1019
0
    target->attributeId = attributeId;
1020
0
}
1021
1022
const char* SOPC_FieldTarget_Get_TargetIndexRange(const SOPC_FieldTarget* target)
1023
0
{
1024
0
    return target->writeIndexRange;
1025
0
}
1026
1027
bool SOPC_FieldTarget_Set_TargetIndexRange(SOPC_FieldTarget* target, const char* targetIndexRange)
1028
0
{
1029
0
    SOPC_ASSERT(NULL != target && NULL != targetIndexRange);
1030
    // free in SOPC_FieldTarget_Clear
1031
0
    target->writeIndexRange = SOPC_PubSub_String_Copy(targetIndexRange);
1032
0
    return (NULL != target->writeIndexRange);
1033
0
}
1034
1035
/** Writer Group **/
1036
const SOPC_PubSubConnection* SOPC_WriterGroup_Get_Connection(const SOPC_WriterGroup* group)
1037
0
{
1038
0
    SOPC_ASSERT(NULL != group);
1039
0
    return group->parent;
1040
0
}
1041
1042
const SOPC_WriterGroup_Options* SOPC_WriterGroup_Get_Options(const SOPC_WriterGroup* group)
1043
0
{
1044
0
    SOPC_ASSERT(NULL != group);
1045
0
    return &group->options;
1046
0
}
1047
1048
void SOPC_WriterGroup_Set_Options(SOPC_WriterGroup* group, const SOPC_WriterGroup_Options* options)
1049
0
{
1050
0
    SOPC_ASSERT(NULL != group);
1051
0
    group->options = *options;
1052
0
}
1053
1054
uint16_t SOPC_WriterGroup_Get_Id(const SOPC_WriterGroup* group)
1055
0
{
1056
0
    SOPC_ASSERT(NULL != group);
1057
0
    return group->id;
1058
0
}
1059
1060
void SOPC_WriterGroup_Set_Id(SOPC_WriterGroup* group, uint16_t id)
1061
0
{
1062
0
    SOPC_ASSERT(NULL != group);
1063
0
    group->id = id;
1064
0
}
1065
1066
uint32_t SOPC_WriterGroup_Get_Version(const SOPC_WriterGroup* group)
1067
0
{
1068
0
    SOPC_ASSERT(NULL != group);
1069
0
    return group->messageSettings.version;
1070
0
}
1071
1072
void SOPC_WriterGroup_Set_Version(SOPC_WriterGroup* group, uint32_t version)
1073
0
{
1074
0
    SOPC_ASSERT(NULL != group);
1075
0
    group->messageSettings.version = version;
1076
0
}
1077
1078
double SOPC_WriterGroup_Get_PublishingInterval(const SOPC_WriterGroup* group)
1079
0
{
1080
0
    SOPC_ASSERT(NULL != group);
1081
0
    return group->publishingIntervalMs;
1082
0
}
1083
1084
int32_t SOPC_WriterGroup_Get_PublishingOffset(const SOPC_WriterGroup* group)
1085
0
{
1086
0
    SOPC_ASSERT(NULL != group);
1087
0
    return group->publishingOffsetMs;
1088
0
}
1089
1090
void SOPC_WriterGroup_Set_PublishingInterval(SOPC_WriterGroup* group, double interval_ms)
1091
0
{
1092
0
    SOPC_ASSERT(NULL != group);
1093
0
    group->publishingIntervalMs = interval_ms;
1094
0
}
1095
1096
void SOPC_WriterGroup_Set_PublishingOffset(SOPC_WriterGroup* group, int32_t offset_ms)
1097
0
{
1098
0
    SOPC_ASSERT(NULL != group);
1099
0
    group->publishingOffsetMs = offset_ms;
1100
0
}
1101
1102
SOPC_UadpNetworkMessageContentMask SOPC_WriterGroup_Get_NetworkMessageContentMask(const SOPC_WriterGroup* group)
1103
0
{
1104
0
    SOPC_ASSERT(NULL != group);
1105
0
    return group->messageSettings.contentMask;
1106
0
}
1107
1108
void SOPC_WriterGroup_Set_NetworkMessageContentMask(SOPC_WriterGroup* group,
1109
                                                    SOPC_UadpNetworkMessageContentMask contentMask)
1110
0
{
1111
0
    SOPC_ASSERT(NULL != group);
1112
0
    group->messageSettings.contentMask = contentMask;
1113
0
}
1114
1115
SOPC_SecurityMode_Type SOPC_WriterGroup_Get_SecurityMode(const SOPC_WriterGroup* group)
1116
0
{
1117
0
    SOPC_ASSERT(NULL != group);
1118
0
    return group->securityMode;
1119
0
}
1120
1121
void SOPC_WriterGroup_Set_SecurityMode(SOPC_WriterGroup* group, SOPC_SecurityMode_Type mode)
1122
0
{
1123
0
    SOPC_ASSERT(NULL != group);
1124
0
    group->securityMode = mode;
1125
0
}
1126
1127
const char* SOPC_WriterGroup_Get_SecurityGroupId(const SOPC_WriterGroup* group)
1128
0
{
1129
0
    SOPC_ASSERT(NULL != group);
1130
0
    return group->securityGroupId;
1131
0
}
1132
1133
void SOPC_WriterGroup_Set_SecurityGroupId(SOPC_WriterGroup* group, const char* securityGroupId)
1134
0
{
1135
0
    SOPC_ASSERT(NULL != group);
1136
0
    if (NULL == securityGroupId)
1137
0
    {
1138
0
        group->securityGroupId = NULL;
1139
0
    }
1140
0
    else
1141
0
    {
1142
0
        group->securityGroupId = SOPC_PubSub_String_Copy(securityGroupId);
1143
0
        SOPC_ASSERT(NULL != group->securityGroupId);
1144
0
    }
1145
0
}
1146
1147
bool SOPC_WriterGroup_Allocate_SecurityKeyServices_Array(SOPC_WriterGroup* group, uint32_t nb)
1148
0
{
1149
0
    SOPC_ASSERT(NULL != group);
1150
    // free in SOPC_WriterGroup_Clear
1151
0
    group->securityKeyServices = SOPC_Calloc(nb, sizeof(SOPC_SecurityKeyServices));
1152
0
    if (NULL == group->securityKeyServices)
1153
0
    {
1154
0
        return false;
1155
0
    }
1156
0
    group->securityKeyServices_length = nb;
1157
0
    return true;
1158
0
}
1159
1160
uint32_t SOPC_WriterGroup_Nb_SecurityKeyServices(const SOPC_WriterGroup* group)
1161
0
{
1162
0
    SOPC_ASSERT(NULL != group);
1163
0
    return group->securityKeyServices_length;
1164
0
}
1165
1166
SOPC_SecurityKeyServices* SOPC_WriterGroup_Get_SecurityKeyServices_At(const SOPC_WriterGroup* group, uint32_t index)
1167
0
{
1168
0
    SOPC_ASSERT(NULL != group);
1169
0
    SOPC_ASSERT(index < group->securityKeyServices_length);
1170
0
    SOPC_ASSERT(NULL != group->securityKeyServices);
1171
0
    return &group->securityKeyServices[index];
1172
0
}
1173
1174
/** SecurityKeyServices **/
1175
1176
const char* SOPC_SecurityKeyServices_Get_EndpointUrl(const SOPC_SecurityKeyServices* sks)
1177
0
{
1178
0
    SOPC_ASSERT(NULL != sks);
1179
0
    return sks->endpointUrl;
1180
0
}
1181
1182
bool SOPC_SecurityKeyServices_Set_EndpointUrl(SOPC_SecurityKeyServices* sks, const char* uri)
1183
0
{
1184
0
    SOPC_ASSERT(NULL != sks);
1185
0
    sks->endpointUrl = SOPC_PubSub_String_Copy(uri);
1186
0
    return (NULL != sks->endpointUrl);
1187
0
}
1188
1189
SOPC_SerializedCertificate* SOPC_SecurityKeyServices_Get_ServerCertificate(const SOPC_SecurityKeyServices* sks)
1190
0
{
1191
0
    SOPC_ASSERT(NULL != sks);
1192
0
    return sks->serverCertificate;
1193
0
}
1194
1195
bool SOPC_SecurityKeyServices_Set_ServerCertificate(SOPC_SecurityKeyServices* sks,
1196
                                                    SOPC_SerializedCertificate* serverCertificate)
1197
0
{
1198
0
    SOPC_ASSERT(NULL != sks);
1199
0
    sks->serverCertificate = serverCertificate;
1200
0
    return (NULL != sks->serverCertificate);
1201
0
}
1202
1203
bool SOPC_WriterGroup_Allocate_DataSetWriter_Array(SOPC_WriterGroup* group, uint8_t nb)
1204
0
{
1205
0
    SOPC_ASSERT(NULL != group);
1206
    // free in SOPC_WriterGroup_Clear
1207
0
    group->dataSetWriters = SOPC_Calloc(nb, sizeof(SOPC_DataSetWriter));
1208
0
    if (NULL == group->dataSetWriters)
1209
0
    {
1210
0
        return false;
1211
0
    }
1212
0
    group->dataSetWriters_length = nb;
1213
0
    return true;
1214
0
}
1215
1216
uint8_t SOPC_WriterGroup_Nb_DataSetWriter(const SOPC_WriterGroup* group)
1217
0
{
1218
0
    SOPC_ASSERT(NULL != group);
1219
0
    return group->dataSetWriters_length;
1220
0
}
1221
1222
SOPC_DataSetWriter* SOPC_WriterGroup_Get_DataSetWriter_At(const SOPC_WriterGroup* group, uint8_t index)
1223
0
{
1224
0
    SOPC_ASSERT(NULL != group && index < group->dataSetWriters_length);
1225
0
    return &group->dataSetWriters[index];
1226
0
}
1227
1228
const char* SOPC_WriterGroup_Get_MqttTopic(const SOPC_WriterGroup* writer)
1229
0
{
1230
0
    SOPC_ASSERT(NULL != writer);
1231
0
    return writer->mqttTopic;
1232
0
}
1233
1234
void SOPC_WriterGroup_Set_MqttTopic(SOPC_WriterGroup* writer, const char* topic)
1235
0
{
1236
0
    SOPC_ASSERT(NULL != writer);
1237
0
    if (NULL != writer->mqttTopic)
1238
0
    {
1239
0
        SOPC_Free(writer->mqttTopic);
1240
0
    }
1241
0
    if (NULL == topic)
1242
0
    {
1243
0
        writer->mqttTopic = NULL;
1244
0
    }
1245
0
    else
1246
0
    {
1247
0
        writer->mqttTopic = SOPC_PubSub_String_Copy(topic);
1248
0
        SOPC_ASSERT(NULL != writer->mqttTopic);
1249
0
    }
1250
0
}
1251
1252
/* Expected only for acyclic publisher */
1253
double SOPC_WriterGroup_Get_KeepAlive(const SOPC_WriterGroup* group)
1254
0
{
1255
0
    SOPC_ASSERT(NULL != group);
1256
0
    return group->keepAliveTimeMs;
1257
0
}
1258
void SOPC_WriterGroup_Set_KeepAlive(SOPC_WriterGroup* group, double keepAlive_ms)
1259
0
{
1260
0
    SOPC_ASSERT(NULL != group);
1261
0
    group->keepAliveTimeMs = keepAlive_ms;
1262
0
}
1263
1264
SOPC_Pubsub_MessageEncodingType SOPC_WriterGroup_Get_Encoding(const SOPC_WriterGroup* group)
1265
0
{
1266
0
    SOPC_ASSERT(NULL != group);
1267
0
    return group->messageEncoding;
1268
0
}
1269
1270
void SOPC_WriterGroup_Set_Encoding(SOPC_WriterGroup* group, SOPC_Pubsub_MessageEncodingType messageEncoding)
1271
0
{
1272
0
    SOPC_ASSERT(NULL != group);
1273
0
    group->messageEncoding = messageEncoding;
1274
0
}
1275
1276
/** DataSetWriter **/
1277
uint16_t SOPC_DataSetWriter_Get_Id(const SOPC_DataSetWriter* writer)
1278
0
{
1279
0
    SOPC_ASSERT(NULL != writer);
1280
0
    return writer->id;
1281
0
}
1282
1283
void SOPC_DataSetWriter_Set_Id(SOPC_DataSetWriter* writer, uint16_t id)
1284
0
{
1285
0
    SOPC_ASSERT(NULL != writer);
1286
0
    writer->id = id;
1287
0
}
1288
1289
const SOPC_DataSetWriter_Options* SOPC_DataSetWriter_Get_Options(const SOPC_DataSetWriter* writer)
1290
0
{
1291
0
    SOPC_ASSERT(NULL != writer);
1292
0
    return &writer->options;
1293
0
}
1294
1295
void SOPC_DataSetWriter_Set_Options(SOPC_DataSetWriter* writer, const SOPC_DataSetWriter_Options* options)
1296
0
{
1297
0
    SOPC_ASSERT(NULL != writer && NULL != options);
1298
0
    writer->options = *options;
1299
0
}
1300
1301
void SOPC_DataSetWriter_Set_DataSet(SOPC_DataSetWriter* writer, SOPC_PublishedDataSet* dataset)
1302
0
{
1303
0
    SOPC_ASSERT(NULL != writer);
1304
0
    writer->dataSet = dataset;
1305
0
}
1306
1307
const SOPC_PublishedDataSet* SOPC_DataSetWriter_Get_DataSet(const SOPC_DataSetWriter* writer)
1308
0
{
1309
0
    SOPC_ASSERT(NULL != writer && NULL != writer->dataSet);
1310
0
    return writer->dataSet;
1311
0
}
1312
1313
/* SOPC_FieldMetaData */
1314
1315
SOPC_FieldTarget* SOPC_FieldMetaData_Get_TargetVariable(const SOPC_FieldMetaData* fieldMetaData)
1316
217
{
1317
217
    SOPC_ASSERT(NULL != fieldMetaData);
1318
217
    return fieldMetaData->targetVariable;
1319
217
}
1320
1321
SOPC_PublishedVariable* SOPC_FieldMetaData_Get_PublishedVariable(const SOPC_FieldMetaData* fieldMetaData)
1322
0
{
1323
0
    SOPC_ASSERT(NULL != fieldMetaData);
1324
0
    return fieldMetaData->publishedVariable;
1325
0
}
1326
1327
int32_t SOPC_FieldMetaData_Get_ValueRank(const SOPC_FieldMetaData* metadata)
1328
14
{
1329
14
    SOPC_ASSERT(NULL != metadata);
1330
14
    return metadata->arrDimension.valueRank;
1331
14
}
1332
1333
SOPC_BuiltinId SOPC_FieldMetaData_Get_BuiltinType(const SOPC_FieldMetaData* metadata)
1334
497
{
1335
497
    SOPC_ASSERT(NULL != metadata);
1336
497
    return metadata->builtinType;
1337
497
}
1338
1339
void SOPC_FieldMetaData_Set_BuiltinType(SOPC_FieldMetaData* metadata, SOPC_BuiltinId builtinType)
1340
18
{
1341
18
    SOPC_ASSERT(NULL != metadata);
1342
18
    metadata->builtinType = builtinType;
1343
18
}
1344
1345
const SOPC_PubSub_ArrayDimension* SOPC_FieldMetaData_Get_ArrayDimension(const SOPC_FieldMetaData* metadata)
1346
11
{
1347
11
    SOPC_ASSERT(NULL != metadata);
1348
11
    return &metadata->arrDimension;
1349
11
}
1350
1351
bool SOPC_FieldMetaDeta_SetCopy_ArrayDimension(SOPC_FieldMetaData* metadata,
1352
                                               const SOPC_PubSub_ArrayDimension* arrayDimensions)
1353
0
{
1354
0
    SOPC_ASSERT(NULL != metadata);
1355
0
    SOPC_ASSERT(NULL != arrayDimensions);
1356
0
    bool res = true;
1357
0
    if (NULL != metadata->arrDimension.arrayDimensions)
1358
0
    {
1359
0
        SOPC_Free(metadata->arrDimension.arrayDimensions);
1360
0
    }
1361
0
    metadata->arrDimension.arrayDimensions = NULL;
1362
0
    if (arrayDimensions->valueRank > 0)
1363
0
    {
1364
0
        metadata->arrDimension.arrayDimensions = SOPC_Calloc((size_t) arrayDimensions->valueRank, sizeof(uint32_t));
1365
0
        if (NULL != metadata->arrDimension.arrayDimensions)
1366
0
        {
1367
0
            memcpy(metadata->arrDimension.arrayDimensions, arrayDimensions->arrayDimensions,
1368
0
                   sizeof(*metadata->arrDimension.arrayDimensions) * (size_t) arrayDimensions->valueRank);
1369
0
        }
1370
0
        else
1371
0
        {
1372
0
            res = false;
1373
0
        }
1374
0
    }
1375
0
    if (res)
1376
0
    {
1377
0
        metadata->arrDimension.valueRank = arrayDimensions->valueRank;
1378
0
    }
1379
0
    return res;
1380
0
}
1381
1382
void SOPC_FieldMetaData_ArrayDimension_Move(SOPC_FieldMetaData* metadata, SOPC_PubSub_ArrayDimension* arrayDimension)
1383
18
{
1384
18
    SOPC_ASSERT(NULL != metadata);
1385
18
    metadata->arrDimension = *arrayDimension;
1386
18
}
1387
1388
/* SOPC_PublishedDataSet */
1389
1390
bool SOPC_PublishedDataSet_Init(SOPC_PublishedDataSet* dataset, SOPC_PublishedDataSetSourceType type, uint16_t nbFields)
1391
0
{
1392
0
    SOPC_ASSERT(NULL != dataset);
1393
0
    dataset->dataSetSourceType = type;
1394
    // free in SOPC_DataSetMetaData_Clear
1395
0
    dataset->dataSetMetaData.fields = SOPC_Calloc(nbFields, sizeof(SOPC_FieldMetaData));
1396
0
    if (NULL == dataset->dataSetMetaData.fields)
1397
0
    {
1398
0
        return false;
1399
0
    }
1400
0
    dataset->dataSetMetaData.fields_length = nbFields;
1401
0
    for (int i = 0; i < nbFields; i++)
1402
0
    {
1403
        // free in SOPC_DataSetMetaData_Clear
1404
0
        SOPC_PublishedVariable* variable = SOPC_Calloc(1, sizeof(SOPC_PublishedVariable));
1405
0
        if (NULL == variable)
1406
0
        {
1407
0
            SOPC_DataSetMetaData_Clear(&(dataset->dataSetMetaData));
1408
0
            return false;
1409
0
        }
1410
0
        dataset->dataSetMetaData.fields[i].publishedVariable = variable;
1411
0
    }
1412
0
    return true;
1413
1414
    ////dataset->dataSetSource.type = type;
1415
    // dataset->dataSetSource.source.dataItems.length = nbFields;
1416
    // dataset->dataSetSource.source.dataItems.publishedData = SOPC_Calloc(nbFields, sizeof(SOPC_PublishedVariable));
1417
0
}
1418
1419
static void SOPC_PublishedDataSet_Clear(SOPC_PublishedDataSet* dataset)
1420
0
{
1421
0
    if (NULL == dataset)
1422
0
    {
1423
0
        return;
1424
0
    }
1425
1426
0
    SOPC_DataSetMetaData_Clear(&(dataset->dataSetMetaData));
1427
    // SOPC_Free(dataset->dataSetSource.source.dataItems.publishedData);
1428
0
}
1429
1430
uint16_t SOPC_PublishedDataSet_Nb_FieldMetaData(const SOPC_PublishedDataSet* dataset)
1431
0
{
1432
0
    SOPC_ASSERT(NULL != dataset);
1433
0
    return dataset->dataSetMetaData.fields_length;
1434
0
}
1435
1436
SOPC_FieldMetaData* SOPC_PublishedDataSet_Get_FieldMetaData_At(const SOPC_PublishedDataSet* dataset, uint16_t index)
1437
0
{
1438
0
    SOPC_ASSERT(NULL != dataset);
1439
0
    SOPC_ASSERT(index < dataset->dataSetMetaData.fields_length);
1440
0
    return &(dataset->dataSetMetaData.fields[index]);
1441
0
}
1442
1443
SOPC_PublishedDataSetSourceType SOPC_PublishedDataSet_Get_DataSet_SourceType(const SOPC_PublishedDataSet* dataset)
1444
0
{
1445
0
    SOPC_ASSERT(NULL != dataset);
1446
0
    return dataset->dataSetSourceType;
1447
0
}
1448
1449
/** SOPC_PublishedVariable **/
1450
1451
const SOPC_NodeId* SOPC_PublishedVariable_Get_NodeId(const SOPC_PublishedVariable* variable)
1452
0
{
1453
0
    SOPC_ASSERT(NULL != variable);
1454
0
    return variable->nodeId;
1455
0
}
1456
1457
void SOPC_PublishedVariable_Set_NodeId(SOPC_PublishedVariable* variable, SOPC_NodeId* nodeId)
1458
0
{
1459
0
    SOPC_ASSERT(NULL != variable && NULL != nodeId);
1460
    // free in SOPC_PublishedVariable_Clear
1461
0
    variable->nodeId = nodeId;
1462
0
}
1463
1464
uint32_t SOPC_PublishedVariable_Get_AttributeId(const SOPC_PublishedVariable* variable)
1465
0
{
1466
0
    SOPC_ASSERT(NULL != variable);
1467
0
    return variable->attributeId;
1468
0
}
1469
1470
void SOPC_PublishedVariable_Set_AttributeId(SOPC_PublishedVariable* variable, uint32_t attributeId)
1471
0
{
1472
0
    SOPC_ASSERT(NULL != variable);
1473
0
    variable->attributeId = attributeId;
1474
0
}
1475
1476
const char* SOPC_PublishedVariable_Get_IndexRange(const SOPC_PublishedVariable* variable)
1477
0
{
1478
0
    return variable->indexRange;
1479
0
}
1480
1481
bool SOPC_PublishedVariable_Set_IndexRange(SOPC_PublishedVariable* variable, const char* indexRange)
1482
0
{
1483
0
    SOPC_ASSERT(NULL != variable && NULL != indexRange);
1484
    // free in SOPC_FieldTarget_Clear
1485
0
    variable->indexRange = SOPC_PubSub_String_Copy(indexRange);
1486
0
    return (NULL != variable->indexRange);
1487
0
}
1488
1489
/* Private */
1490
1491
static char* SOPC_PubSub_String_Copy(const char* src)
1492
0
{
1493
0
    SOPC_ASSERT(NULL != src);
1494
0
    char* dst = SOPC_Malloc((strlen(src) + 1) * sizeof(char));
1495
0
    if (NULL != dst)
1496
0
    {
1497
0
        strcpy(dst, src);
1498
0
    }
1499
0
    return dst;
1500
0
}
1501
1502
static void SOPC_WriterGroup_Clear(SOPC_WriterGroup* group)
1503
0
{
1504
0
    if (NULL != group)
1505
0
    {
1506
0
        SOPC_Free(group->securityGroupId);
1507
        // securityKeyServices_length /= 0 => securityKeyServices /= NULL
1508
0
        SOPC_ASSERT(0 == group->securityKeyServices_length || NULL != group->securityKeyServices);
1509
0
        for (uint32_t i = 0; i < group->securityKeyServices_length; i++)
1510
0
        {
1511
0
            SOPC_SecurityKeyServices_Clear(&group->securityKeyServices[i]);
1512
0
        }
1513
0
        SOPC_Free(group->securityKeyServices);
1514
0
        group->securityKeyServices = NULL;
1515
0
        group->securityKeyServices_length = 0;
1516
0
        group->dataSetWriters_length = 0;
1517
        /* IMPORTANT NOTE: No memory management to do in dataSetWriter(s), publishedDataSet managed in config struct
1518
         * => no need to iterate on array */
1519
0
        SOPC_Free(group->dataSetWriters);
1520
0
        SOPC_Free(group->mqttTopic);
1521
0
        group->dataSetWriters = NULL;
1522
0
        group->mqttTopic = NULL;
1523
0
    }
1524
0
}
1525
1526
static void SOPC_SecurityKeyServices_Clear(SOPC_SecurityKeyServices* sks)
1527
0
{
1528
0
    if (NULL == sks)
1529
0
    {
1530
0
        return;
1531
0
    }
1532
1533
0
    SOPC_Free(sks->endpointUrl);
1534
0
    sks->endpointUrl = NULL;
1535
0
    SOPC_KeyManager_SerializedCertificate_Delete(sks->serverCertificate);
1536
0
    sks->serverCertificate = NULL;
1537
0
}
1538
1539
static void SOPC_ReaderGroup_Clear(SOPC_ReaderGroup* group)
1540
0
{
1541
0
    if (NULL != group)
1542
0
    {
1543
0
        SOPC_Free(group->securityGroupId);
1544
1545
        // securityKeyServices_length /= 0 => securityKeyServices /= NULL
1546
0
        SOPC_ASSERT(0 == group->securityKeyServices_length || NULL != group->securityKeyServices);
1547
0
        for (uint32_t i = 0; i < group->securityKeyServices_length; i++)
1548
0
        {
1549
0
            SOPC_SecurityKeyServices_Clear(&group->securityKeyServices[i]);
1550
0
        }
1551
0
        SOPC_Free(group->securityKeyServices);
1552
0
        group->securityKeyServices = NULL;
1553
0
        group->securityKeyServices_length = 0;
1554
1555
0
        for (int i = 0; i < group->dataSetReaders_length; i++)
1556
0
        {
1557
0
            SOPC_DataSetMetaData_Clear(&(group->dataSetReaders[i].metaData));
1558
0
        }
1559
0
        group->dataSetReaders_length = 0;
1560
0
        SOPC_Free(group->dataSetReaders);
1561
0
        SOPC_Free(group->mqttTopic);
1562
0
        SOPC_String_Clear(&group->publisherId.data.string);
1563
0
    }
1564
0
}
1565
1566
static void SOPC_FieldTarget_Clear(SOPC_FieldTarget* target)
1567
0
{
1568
0
    if (NULL != target)
1569
0
    {
1570
0
        SOPC_Free(target->receiverIndexRange);
1571
0
        SOPC_NodeId_Clear(target->nodeId);
1572
0
        SOPC_Free(target->nodeId);
1573
0
        SOPC_Free(target->writeIndexRange);
1574
0
    }
1575
0
}
1576
1577
static void SOPC_PublishedVariable_Clear(SOPC_PublishedVariable* variable)
1578
0
{
1579
0
    if (NULL != variable)
1580
0
    {
1581
0
        SOPC_NodeId_Clear(variable->nodeId);
1582
0
        SOPC_Free(variable->nodeId);
1583
0
    }
1584
0
}
1585
1586
/* Helper Functions*/
1587
1588
bool SOPC_EndpointDescription_Create_From_URL(char* url, OpcUa_EndpointDescription** endpoint_out)
1589
0
{
1590
0
    SOPC_ASSERT(NULL != endpoint_out);
1591
0
    *endpoint_out = NULL;
1592
1593
0
    bool allocSuccess = true;
1594
0
    OpcUa_EndpointDescription* endpoint;
1595
0
    if (NULL == url)
1596
0
    {
1597
0
        return true;
1598
0
    }
1599
0
    endpoint = SOPC_Calloc(1, sizeof(OpcUa_EndpointDescription));
1600
0
    if (NULL == endpoint)
1601
0
    {
1602
0
        return false;
1603
0
    }
1604
1605
0
    OpcUa_EndpointDescription_Initialize(endpoint);
1606
0
    SOPC_String_Initialize(&endpoint->EndpointUrl);
1607
0
    SOPC_ReturnStatus status = SOPC_String_CopyFromCString(&endpoint->EndpointUrl, url);
1608
0
    if (SOPC_STATUS_OK == status)
1609
0
    {
1610
0
        *endpoint_out = endpoint;
1611
0
    }
1612
0
    else
1613
0
    {
1614
        allocSuccess = false;
1615
0
        SOPC_Free(endpoint);
1616
0
    }
1617
0
    return allocSuccess;
1618
0
}