Coverage Report

Created: 2026-05-16 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/plugins/ua_config_json.c
Line
Count
Source
1
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
2
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
3
 *
4
 *    Copyright 2023 (c) Fraunhofer IOSB (Author: Noel Graf)
5
 *    Copyright 2025 (c) o6 Automation GmbH (Author: Julius Pfrommer)
6
 */
7
8
#include <open62541/plugin/log.h>
9
#include <open62541/server_config_file_based.h>
10
#include "cj5.h"
11
#include "open62541/server_config_default.h"
12
#ifdef UA_ENABLE_ENCRYPTION
13
#include "open62541/plugin/certificategroup_default.h"
14
#endif
15
16
2.14k
#define MAX_TOKENS 1024
17
18
typedef struct {
19
    const char *json;
20
    const cj5_token *tokens;
21
    size_t tokensSize;
22
    size_t index;
23
    UA_Byte depth;
24
    cj5_result result;
25
26
    UA_Logger *logging;
27
} ParsingCtx;
28
29
static UA_ByteString
30
50
getJsonPart(cj5_token tok, const char *json) {
31
50
    UA_ByteString bs;
32
50
    UA_ByteString_init(&bs);
33
50
    if(tok.type == CJ5_TOKEN_STRING) {
34
0
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start - 1);
35
0
        bs.length = (tok.end - tok.start) + 3;
36
0
        return bs;
37
50
    } else {
38
50
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start);
39
50
        bs.length = (tok.end - tok.start) + 1;
40
50
        return bs;
41
50
    }
42
50
}
43
44
/* Forward declarations*/
45
#define PARSE_JSON(TYPE) static UA_StatusCode                   \
46
    TYPE##_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize)
47
48
typedef UA_StatusCode
49
(*parseJsonSignature)(ParsingCtx *ctx, void *configField, size_t *configFieldSize);
50
51
#ifdef UA_ENABLE_ENCRYPTION
52
static UA_ByteString
53
loadCertificateFile(const char *const path);
54
#endif
55
56
/* The DataType "kind" is an internal type classification. It is used to
57
 * dispatch handling to the correct routines. */
58
#define UA_SERVERCONFIGFIELDKINDS 25
59
typedef enum {
60
    /* Basic Types */
61
    UA_SERVERCONFIGFIELD_INT64 = 0,
62
    UA_SERVERCONFIGFIELD_UINT16,
63
    UA_SERVERCONFIGFIELD_UINT32,
64
    UA_SERVERCONFIGFIELD_UINT64,
65
    UA_SERVERCONFIGFIELD_STRING,
66
    UA_SERVERCONFIGFIELD_LOCALIZEDTEXT,
67
    UA_SERVERCONFIGFIELD_DOUBLE,
68
    UA_SERVERCONFIGFIELD_BOOLEAN,
69
    UA_SERVERCONFIGFIELD_DURATION,
70
    UA_SERVERCONFIGFIELD_DURATIONRANGE,
71
    UA_SERVERCONFIGFIELD_UINT32RANGE,
72
73
    /* Advanced Types */
74
    UA_SERVERCONFIGFIELD_BUILDINFO,
75
    UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION,
76
    UA_SERVERCONFIGFIELD_STRINGARRAY,
77
    UA_SERVERCONFIGFIELD_UINT32ARRAY,
78
    UA_SERVERCONFIGFIELD_DATETIME,
79
    UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION,
80
    UA_SERVERCONFIGFIELD_TCPCONFIGURATION,
81
    UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION,
82
    UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION,
83
    UA_SERVERCONFIGFIELD_MDNSCONFIGURATION,
84
    UA_SERVERCONFIGFIELD_SECURITYPOLICIES,
85
    UA_SERVERCONFIGFIELD_SECURITYPKI,
86
87
    /* Enumerations */
88
    UA_SERVERCONFIGFIELD_APPLICATIONTYPE,
89
    UA_SERVERCONFIGFIELD_RULEHANDLING
90
} UA_ServerConfigFieldKind;
91
92
extern const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS];
93
94
/*----------------------Basic Types------------------------*/
95
0
PARSE_JSON(Int64Field) {
96
0
    cj5_token tok = ctx->tokens[++ctx->index];
97
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
98
0
    UA_Int64 out;
99
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_INT64], NULL);
100
0
    if(retval != UA_STATUSCODE_GOOD)
101
0
        return retval;
102
0
    UA_Int64 *field = (UA_Int64*)configField;
103
0
    *field = out;
104
0
    return retval;
105
0
}
106
0
PARSE_JSON(UInt16Field) {
107
0
    cj5_token tok = ctx->tokens[++ctx->index];
108
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
109
0
    UA_UInt16 out;
110
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT16], NULL);
111
0
    if(retval != UA_STATUSCODE_GOOD)
112
0
        return retval;
113
0
    UA_UInt16 *field = (UA_UInt16*)configField;
114
0
    *field = out;
115
0
    return retval;
116
0
}
117
40
PARSE_JSON(UInt32Field) {
118
40
    cj5_token tok = ctx->tokens[++ctx->index];
119
40
    UA_ByteString buf = getJsonPart(tok, ctx->json);
120
40
    UA_UInt32 out;
121
40
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT32], NULL);
122
40
    if(retval != UA_STATUSCODE_GOOD)
123
36
        return retval;
124
4
    UA_UInt32 *field = (UA_UInt32*)configField;
125
4
    *field = out;
126
4
    return retval;
127
40
}
128
5
PARSE_JSON(UInt64Field) {
129
5
    cj5_token tok = ctx->tokens[++ctx->index];
130
5
    UA_ByteString buf = getJsonPart(tok, ctx->json);
131
5
    UA_UInt64 out;
132
5
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT64], NULL);
133
5
    if(retval != UA_STATUSCODE_GOOD)
134
3
        return retval;
135
2
    UA_UInt64 *field = (UA_UInt64*)configField;
136
2
    *field = out;
137
2
    return retval;
138
5
}
139
0
PARSE_JSON(StringField) {
140
0
    cj5_token tok = ctx->tokens[++ctx->index];
141
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
142
0
    UA_String out;
143
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_STRING], NULL);
144
0
    if(retval != UA_STATUSCODE_GOOD)
145
0
        return retval;
146
0
    UA_String *field = (UA_String*)configField;
147
0
    if(field != NULL) {
148
0
        UA_String_clear(field);
149
0
        *field = out;
150
0
    }
151
0
    return retval;
152
0
}
153
0
PARSE_JSON(LocalizedTextField) {
154
    /*
155
     applicationName: {
156
        locale: "de-DE",
157
        text: "Test text"
158
    }
159
     */
160
0
    cj5_token tok = ctx->tokens[++ctx->index];
161
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
162
0
    UA_String locale = {.length = 0, .data = NULL};
163
0
    UA_String text = {.length = 0, .data = NULL};
164
0
    for(size_t j = tok.size/2; j > 0; j--) {
165
0
        tok = ctx->tokens[++ctx->index];
166
0
        switch (tok.type) {
167
0
        case CJ5_TOKEN_STRING: {
168
0
            char *field = (char*)UA_malloc(tok.size + 1);
169
0
            unsigned int str_len = 0;
170
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field, &str_len);
171
172
0
            tok = ctx->tokens[++ctx->index];
173
0
            UA_ByteString buf = getJsonPart(tok, ctx->json);
174
0
            if(strcmp(field, "locale") == 0)
175
0
                retval |= UA_decodeJson(&buf, &locale, &UA_TYPES[UA_TYPES_STRING], NULL);
176
0
            else if(strcmp(field, "text") == 0)
177
0
                retval |= UA_decodeJson(&buf, &text, &UA_TYPES[UA_TYPES_STRING], NULL);
178
0
            else {
179
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
180
0
            }
181
0
            UA_free(field);
182
0
            break;
183
0
        }
184
0
        default:
185
0
            break;
186
0
        }
187
0
    }
188
0
    UA_LocalizedText out;
189
0
    out.locale = locale;
190
0
    out.text = text;
191
0
    if(retval != UA_STATUSCODE_GOOD)
192
0
        return retval;
193
0
    UA_LocalizedText *field = (UA_LocalizedText*)configField;
194
0
    if(field != NULL) {
195
0
        UA_LocalizedText_clear(field);
196
0
        *field = out;
197
0
    }
198
0
    return retval;
199
0
}
200
0
PARSE_JSON(DoubleField) {
201
0
    cj5_token tok = ctx->tokens[++ctx->index];
202
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
203
0
    UA_Double out;
204
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DOUBLE], NULL);
205
0
    if(retval != UA_STATUSCODE_GOOD)
206
0
        return retval;
207
0
    UA_Double *field = (UA_Double *)configField;
208
0
    *field = out;
209
0
    return retval;
210
0
}
211
5
PARSE_JSON(BooleanField) {
212
5
    cj5_token tok = ctx->tokens[++ctx->index];
213
5
    UA_ByteString buf = getJsonPart(tok, ctx->json);
214
5
    UA_Boolean out;
215
5
    if(tok.type != CJ5_TOKEN_BOOL) {
216
5
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Value of type bool expected.");
217
5
        return UA_STATUSCODE_BADTYPEMISMATCH;
218
5
    }
219
0
    UA_String val = UA_STRING("true");
220
0
    if(UA_String_equal(&val, &buf)) {
221
0
        out = true;
222
0
    }else {
223
0
        out = false;
224
0
    }
225
    /* set server config field */
226
0
    UA_Boolean *field = (UA_Boolean *)configField;
227
0
    *field = out;
228
0
    return UA_STATUSCODE_GOOD;
229
5
}
230
0
PARSE_JSON(DurationField) {
231
0
    UA_Double double_value;
232
0
    UA_StatusCode retval = DoubleField_parseJson(ctx, &double_value, NULL);
233
0
    if(retval != UA_STATUSCODE_GOOD)
234
0
        return retval;
235
0
    UA_Duration *field = (UA_Duration*)configField;
236
0
    *field = (UA_Duration)double_value;
237
0
    return retval;
238
0
}
239
0
PARSE_JSON(DurationRangeField) {
240
0
    UA_DurationRange *field = (UA_DurationRange*)configField;
241
0
    cj5_token tok = ctx->tokens[++ctx->index];
242
0
    for(size_t j = tok.size/2; j > 0; j--) {
243
0
        tok = ctx->tokens[++ctx->index];
244
0
        switch (tok.type) {
245
0
        case CJ5_TOKEN_STRING: {
246
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
247
0
            unsigned int str_len = 0;
248
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
249
0
            if(strcmp(field_str, "min") == 0)
250
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->min, NULL);
251
0
            else if(strcmp(field_str, "max") == 0)
252
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->max, NULL);
253
0
            else {
254
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
255
0
            }
256
0
            UA_free(field_str);
257
0
            break;
258
0
        }
259
0
        default:
260
0
            break;
261
0
        }
262
0
    }
263
0
    return UA_STATUSCODE_GOOD;
264
0
}
265
0
PARSE_JSON(UInt32RangeField) {
266
0
    UA_UInt32Range *field = (UA_UInt32Range*)configField;
267
0
    cj5_token tok = ctx->tokens[++ctx->index];
268
0
    for(size_t j = tok.size/2; j > 0; j--) {
269
0
        tok = ctx->tokens[++ctx->index];
270
0
        switch (tok.type) {
271
0
        case CJ5_TOKEN_STRING: {
272
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
273
0
            unsigned int str_len = 0;
274
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
275
0
            if(strcmp(field_str, "min") == 0)
276
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->min, NULL);
277
0
            else if(strcmp(field_str, "max") == 0)
278
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->max, NULL);
279
0
            else {
280
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
281
0
            }
282
0
            UA_free(field_str);
283
0
            break;
284
0
        }
285
0
        default:
286
0
            break;
287
0
        }
288
0
    }
289
0
    return UA_STATUSCODE_GOOD;
290
0
}
291
292
/*----------------------Advanced Types------------------------*/
293
19
PARSE_JSON(BuildInfo) {
294
19
    UA_BuildInfo *field = (UA_BuildInfo*)configField;
295
19
    cj5_token tok = ctx->tokens[++ctx->index];
296
1.33k
    for(size_t j = tok.size/2; j > 0; j--) {
297
1.32k
        tok = ctx->tokens[++ctx->index];
298
1.32k
        switch (tok.type) {
299
239
        case CJ5_TOKEN_STRING: {
300
239
            char *field_str = (char*)UA_malloc(tok.size + 1);
301
239
            unsigned int str_len = 0;
302
239
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
303
239
            if(strcmp(field_str, "productUri") == 0)
304
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
305
239
            else if(strcmp(field_str, "manufacturerName") == 0)
306
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->manufacturerName, NULL);
307
239
            else if(strcmp(field_str, "productName") == 0)
308
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productName, NULL);
309
239
            else if(strcmp(field_str, "softwareVersion") == 0)
310
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->softwareVersion, NULL);
311
239
            else if(strcmp(field_str, "buildNumber") == 0)
312
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->buildNumber, NULL);
313
239
            else if(strcmp(field_str, "buildDate") == 0)
314
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DATETIME](ctx, &field->buildDate, NULL);
315
239
            else {
316
239
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
317
239
            }
318
239
            UA_free(field_str);
319
239
            break;
320
0
        }
321
1.08k
        default:
322
1.08k
            break;
323
1.32k
        }
324
1.32k
    }
325
19
    return UA_STATUSCODE_GOOD;
326
19
}
327
0
PARSE_JSON(ApplicationDescriptionField) {
328
0
    UA_ApplicationDescription *field = (UA_ApplicationDescription*)configField;
329
0
    cj5_token tok = ctx->tokens[++ctx->index];
330
0
    for(size_t j = tok.size/2; j > 0; j--) {
331
0
        tok = ctx->tokens[++ctx->index];
332
0
        switch (tok.type) {
333
0
        case CJ5_TOKEN_STRING: {
334
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
335
0
            unsigned int str_len = 0;
336
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
337
0
            if(strcmp(field_str, "applicationUri") == 0)
338
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->applicationUri, NULL);
339
0
            else if(strcmp(field_str, "productUri") == 0)
340
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
341
0
            else if(strcmp(field_str, "applicationName") == 0)
342
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_LOCALIZEDTEXT](ctx, &field->applicationName, NULL);
343
0
            else if(strcmp(field_str, "applicationType") == 0)
344
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONTYPE](ctx, &field->applicationType, NULL);
345
0
            else if(strcmp(field_str, "gatewayServerUri") == 0)
346
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->gatewayServerUri, NULL);
347
0
            else if(strcmp(field_str, "discoveryProfileUri") == 0)
348
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->discoveryProfileUri, NULL);
349
0
            else if(strcmp(field_str, "discoveryUrls") == 0)
350
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &field->discoveryUrls, &field->discoveryUrlsSize);
351
0
            else {
352
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
353
0
            }
354
0
            UA_free(field_str);
355
0
            break;
356
0
        }
357
0
        default:
358
0
            break;
359
0
        }
360
0
    }
361
0
    return UA_STATUSCODE_GOOD;
362
0
}
363
0
PARSE_JSON(StringArrayField) {
364
0
    if(configFieldSize == NULL) {
365
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Pointer to the array size is not set.");
366
0
        return UA_STATUSCODE_BADARGUMENTSMISSING;
367
0
    }
368
0
    cj5_token tok = ctx->tokens[++ctx->index];
369
0
    UA_String *stringArray = (UA_String*)UA_malloc(sizeof(UA_String) * tok.size);
370
0
    size_t stringArraySize = 0;
371
0
    for(size_t j = tok.size; j > 0; j--) {
372
0
        UA_String out = {.length = 0, .data = NULL};
373
0
        parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
374
0
        UA_String_copy(&out, &stringArray[stringArraySize++]);
375
0
        UA_String_clear(&out);
376
0
    }
377
    /* Add to the config */
378
0
    UA_String **field = (UA_String**)configField;
379
0
    if(*configFieldSize > 0) {
380
0
        UA_Array_delete(*field, *configFieldSize,
381
0
                        &UA_TYPES[UA_TYPES_STRING]);
382
0
        *field = NULL;
383
0
        *configFieldSize = 0;
384
0
    }
385
0
    UA_StatusCode retval =
386
0
        UA_Array_copy(stringArray, stringArraySize,
387
0
                      (void**)field, &UA_TYPES[UA_TYPES_STRING]);
388
0
    *configFieldSize = stringArraySize;
389
390
    /* Clean up */
391
0
    UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
392
0
    return retval;
393
0
}
394
0
PARSE_JSON(UInt32ArrayField) {
395
0
    if(configFieldSize == NULL) {
396
0
        UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Pointer to the array size is not set.");
397
0
        return UA_STATUSCODE_BADARGUMENTSMISSING;
398
0
    }
399
0
    cj5_token tok = ctx->tokens[++ctx->index];
400
0
    UA_UInt32 *numberArray = (UA_UInt32*)UA_malloc(sizeof(UA_UInt32) * tok.size);
401
0
    size_t numberArraySize = 0;
402
0
    for(size_t j = tok.size; j > 0; j--) {
403
0
        UA_UInt32 value;
404
0
        UA_StatusCode retval = UInt32Field_parseJson(ctx, &value, NULL);
405
0
        if(retval != UA_STATUSCODE_GOOD)
406
0
            continue;
407
0
        numberArray[numberArraySize++] = value;
408
0
    }
409
    /* Add to the config */
410
0
    UA_UInt32 **field = (UA_UInt32**)configField;
411
0
    if(*configFieldSize > 0) {
412
0
        UA_Array_delete(*field, *configFieldSize,
413
0
                        &UA_TYPES[UA_TYPES_UINT32]);
414
0
        *field = NULL;
415
0
        *configFieldSize = 0;
416
0
    }
417
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
418
0
    if(numberArraySize > 0) {
419
0
        retval = UA_Array_copy(numberArray, numberArraySize,
420
0
                          (void **)field, &UA_TYPES[UA_TYPES_UINT32]);
421
0
        *configFieldSize = numberArraySize;
422
0
    }
423
    /* Clean up */
424
0
    UA_Array_delete(numberArray, numberArraySize, &UA_TYPES[UA_TYPES_UINT32]);
425
0
    return retval;
426
0
}
427
0
PARSE_JSON(DateTimeField) {
428
0
    cj5_token tok = ctx->tokens[++ctx->index];
429
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
430
0
    UA_DateTime out;
431
0
    UA_DateTime_init(&out);
432
0
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DATETIME], NULL);
433
0
    if(retval != UA_STATUSCODE_GOOD)
434
0
        return retval;
435
0
    UA_DateTime *field = (UA_DateTime*)configField;
436
0
    *field = out;
437
0
    return retval;
438
0
}
439
440
685
PARSE_JSON(MdnsConfigurationField) {
441
685
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
442
685
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
443
685
    cj5_token tok = ctx->tokens[++ctx->index];
444
4.47k
    for(size_t j = tok.size/2; j > 0; j--) {
445
3.79k
        tok = ctx->tokens[++ctx->index];
446
3.79k
        switch (tok.type) {
447
2.13k
        case CJ5_TOKEN_STRING: {
448
2.13k
            char *field_str = (char*)UA_malloc(tok.size + 1);
449
2.13k
            unsigned int str_len = 0;
450
2.13k
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
451
2.13k
            if(strcmp(field_str, "mdnsServerName") == 0)
452
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsConfig.mdnsServerName, NULL);
453
2.13k
            else if(strcmp(field_str, "serverCapabilities") == 0)
454
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &config->mdnsConfig.serverCapabilities, &config->mdnsConfig.serverCapabilitiesSize);
455
2.13k
#ifdef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD
456
2.13k
            else if(strcmp(field_str, "mdnsInterfaceIP") == 0)
457
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsInterfaceIP, NULL);
458
            /* mdnsIpAddressList and mdnsIpAddressListSize are only available if UA_HAS_GETIFADDR is not defined: */
459
# if !defined(UA_HAS_GETIFADDR)
460
            else if(strcmp(field_str, "mdnsIpAddressList") == 0)
461
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32ARRAY](ctx, &config->mdnsIpAddressList, &config->mdnsIpAddressListSize);
462
# endif
463
2.13k
#endif
464
2.13k
            else {
465
2.13k
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
466
2.13k
            }
467
2.13k
            UA_free(field_str);
468
2.13k
            break;
469
0
        }
470
1.66k
        default:
471
1.66k
        break;
472
3.79k
        }
473
3.79k
    }
474
685
#endif
475
685
    return UA_STATUSCODE_GOOD;
476
685
}
477
478
0
PARSE_JSON(SubscriptionConfigurationField) {
479
0
#ifdef UA_ENABLE_SUBSCRIPTIONS
480
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
481
0
    cj5_token tok = ctx->tokens[++ctx->index];
482
0
    for(size_t j = tok.size/2; j > 0; j--) {
483
0
        tok = ctx->tokens[++ctx->index];
484
0
        switch (tok.type) {
485
0
        case CJ5_TOKEN_STRING: {
486
0
            char *field_str = (char*)UA_malloc(tok.size + 1);
487
0
            unsigned int str_len = 0;
488
0
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
489
0
            if(strcmp(field_str, "maxSubscriptions") == 0)
490
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptions, NULL);
491
0
            else if(strcmp(field_str, "maxSubscriptionsPerSession") == 0)
492
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptionsPerSession, NULL);
493
0
            else if(strcmp(field_str, "publishingIntervalLimits") == 0)
494
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->publishingIntervalLimits, NULL);
495
0
            else if(strcmp(field_str, "lifeTimeCountLimits") == 0)
496
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->lifeTimeCountLimits, NULL);
497
0
            else if(strcmp(field_str, "keepAliveCountLimits") == 0)
498
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->keepAliveCountLimits, NULL);
499
0
            else if(strcmp(field_str, "maxNotificationsPerPublish") == 0)
500
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxNotificationsPerPublish, NULL);
501
0
            else if(strcmp(field_str, "enableRetransmissionQueue") == 0)
502
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->enableRetransmissionQueue, NULL);
503
0
            else if(strcmp(field_str, "maxRetransmissionQueueSize") == 0)
504
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxRetransmissionQueueSize, NULL);
505
0
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
506
0
            else if(strcmp(field_str, "maxEventsPerNode") == 0)
507
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxEventsPerNode, NULL);
508
0
# endif
509
0
            else if(strcmp(field_str, "maxMonitoredItems") == 0)
510
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItems, NULL);
511
0
            else if(strcmp(field_str, "maxMonitoredItemsPerSubscription") == 0)
512
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItemsPerSubscription, NULL);
513
0
            else if(strcmp(field_str, "samplingIntervalLimits") == 0)
514
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->samplingIntervalLimits, NULL);
515
0
            else if(strcmp(field_str, "queueSizeLimits") == 0)
516
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->queueSizeLimits, NULL);
517
0
            else if(strcmp(field_str, "maxPublishReqPerSession") == 0)
518
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxPublishReqPerSession, NULL);
519
0
            else {
520
0
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
521
0
            }
522
0
            UA_free(field_str);
523
0
            break;
524
0
        }
525
0
        default:
526
0
            break;
527
0
        }
528
0
    }
529
0
#endif
530
0
    return UA_STATUSCODE_GOOD;
531
0
}
532
533
26
PARSE_JSON(TcpConfigurationField) {
534
26
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
535
26
    cj5_token tok = ctx->tokens[++ctx->index];
536
1.71k
    for(size_t j = tok.size/2; j > 0; j--) {
537
1.68k
        tok = ctx->tokens[++ctx->index];
538
1.68k
        switch (tok.type) {
539
297
        case CJ5_TOKEN_STRING: {
540
297
            char *field_str = (char*)UA_malloc(tok.size + 1);
541
297
            unsigned int str_len = 0;
542
297
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
543
297
            if(strcmp(field_str, "tcpBufSize") == 0)
544
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpBufSize, NULL);
545
297
            else if(strcmp(field_str, "tcpMaxMsgSize") == 0)
546
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxMsgSize, NULL);
547
297
            else if(strcmp(field_str, "tcpMaxChunks") == 0)
548
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxChunks, NULL);
549
297
            else {
550
297
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
551
297
            }
552
297
            UA_free(field_str);
553
297
            break;
554
0
        }
555
1.39k
        default:
556
1.39k
            break;
557
1.68k
        }
558
1.68k
    }
559
26
    return UA_STATUSCODE_GOOD;
560
26
}
561
562
3
PARSE_JSON(PubsubConfigurationField) {
563
3
#ifdef UA_ENABLE_PUBSUB
564
3
    UA_PubSubConfiguration *field = (UA_PubSubConfiguration*)configField;
565
3
    cj5_token tok = ctx->tokens[++ctx->index];
566
8
    for(size_t j = tok.size/2; j > 0; j--) {
567
5
        tok = ctx->tokens[++ctx->index];
568
5
        switch (tok.type) {
569
3
        case CJ5_TOKEN_STRING: {
570
3
            char *field_str = (char*)UA_malloc(tok.size + 1);
571
3
            unsigned int str_len = 0;
572
3
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
573
3
            if(strcmp(field_str, "enableDeltaFrames") == 0)
574
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableDeltaFrames, NULL);
575
3
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
576
3
            else if(strcmp(field_str, "enableInformationModelMethods") == 0)
577
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableInformationModelMethods, NULL);
578
3
#endif
579
3
            else {
580
3
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
581
3
            }
582
3
            UA_free(field_str);
583
3
            break;
584
0
        }
585
2
        default:
586
2
            break;
587
5
        }
588
5
    }
589
3
#endif
590
3
    return UA_STATUSCODE_GOOD;
591
3
}
592
593
1
PARSE_JSON(HistorizingConfigurationField) {
594
1
#ifdef UA_ENABLE_HISTORIZING
595
1
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
596
1
    cj5_token tok = ctx->tokens[++ctx->index];
597
2
    for(size_t j = tok.size/2; j > 0; j--) {
598
1
        tok = ctx->tokens[++ctx->index];
599
1
        switch (tok.type) {
600
1
        case CJ5_TOKEN_STRING: {
601
1
            char *field_str = (char*)UA_malloc(tok.size + 1);
602
1
            unsigned int str_len = 0;
603
1
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
604
1
            if(strcmp(field_str, "accessHistoryDataCapability") == 0)
605
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryDataCapability, NULL);
606
1
            else if(strcmp(field_str, "maxReturnDataValues") == 0)
607
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnDataValues, NULL);
608
1
            else if(strcmp(field_str, "accessHistoryEventsCapability") == 0)
609
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryEventsCapability, NULL);
610
1
            else if(strcmp(field_str, "maxReturnEventValues") == 0)
611
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnEventValues, NULL);
612
1
            else if(strcmp(field_str, "insertDataCapability") == 0)
613
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertDataCapability, NULL);
614
1
            else if(strcmp(field_str, "insertEventCapability") == 0)
615
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertEventCapability, NULL);
616
1
            else if(strcmp(field_str, "insertAnnotationsCapability") == 0)
617
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertAnnotationsCapability, NULL);
618
1
            else if(strcmp(field_str, "replaceDataCapability") == 0)
619
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceDataCapability, NULL);
620
1
            else if(strcmp(field_str, "replaceEventCapability") == 0)
621
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceEventCapability, NULL);
622
1
            else if(strcmp(field_str, "updateDataCapability") == 0)
623
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateDataCapability, NULL);
624
1
            else if(strcmp(field_str, "updateEventCapability") == 0)
625
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateEventCapability, NULL);
626
1
            else if(strcmp(field_str, "deleteRawCapability") == 0)
627
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteRawCapability, NULL);
628
1
            else if(strcmp(field_str, "deleteEventCapability") == 0)
629
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteEventCapability, NULL);
630
1
            else if(strcmp(field_str, "deleteAtTimeDataCapability") == 0)
631
0
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteAtTimeDataCapability, NULL);
632
1
            else {
633
1
                UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
634
1
            }
635
1
            UA_free(field_str);
636
1
            break;
637
0
        }
638
0
        default:
639
0
            break;
640
1
        }
641
1
    }
642
1
#endif
643
1
    return UA_STATUSCODE_GOOD;
644
1
}
645
646
0
PARSE_JSON(SecurityPolciesField) {
647
0
#ifdef UA_ENABLE_ENCRYPTION
648
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
649
650
0
    UA_String noneuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
651
0
    UA_String basic128Rsa15uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
652
0
    UA_String basic256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
653
0
    UA_String basic256Sha256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
654
0
    UA_String aes128sha256rsaoaepuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
655
0
    UA_String aes256sha256rsapssuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
656
657
0
    cj5_token tok = ctx->tokens[++ctx->index];
658
0
    for(size_t j = tok.size; j > 0; j--) {
659
660
0
        UA_String policy = {.length = 0, .data = NULL};
661
0
        UA_ByteString certificate = {.length = 0, .data = NULL};
662
0
        UA_ByteString privateKey = {.length = 0, .data = NULL};
663
664
0
        tok = ctx->tokens[++ctx->index];
665
0
        for(size_t i = tok.size / 2; i > 0; i--) {
666
0
            tok = ctx->tokens[++ctx->index];
667
0
            switch(tok.type) {
668
0
            case CJ5_TOKEN_STRING: {
669
0
                char *field_str = (char *)UA_malloc(tok.size + 1);
670
0
                unsigned int str_len = 0;
671
0
                cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
672
0
                if(strcmp(field_str, "certificate") == 0) {
673
0
                    UA_String out = {.length = 0, .data = NULL};
674
0
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
675
676
0
                    if(out.length > 0) {
677
0
                        char *certfile = (char *)UA_malloc(out.length + 1);
678
0
                        memcpy(certfile, out.data, out.length);
679
0
                        certfile[out.length] = '\0';
680
0
                        certificate = loadCertificateFile(certfile);
681
0
                        UA_String_clear(&out);
682
0
                        UA_free(certfile);
683
0
                    }
684
0
                } else if(strcmp(field_str, "privateKey") == 0) {
685
0
                    UA_String out = {.length = 0, .data = NULL};
686
0
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
687
688
0
                    if(out.length > 0) {
689
0
                        char *keyfile = (char *)UA_malloc(out.length + 1);
690
0
                        memcpy(keyfile, out.data, out.length);
691
0
                        keyfile[out.length] = '\0';
692
0
                        privateKey = loadCertificateFile(keyfile);
693
0
                        UA_String_clear(&out);
694
0
                        UA_free(keyfile);
695
0
                    }
696
0
                } else if(strcmp(field_str, "policy") == 0) {
697
0
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &policy, NULL);
698
0
                } else {
699
0
                    UA_LOG_ERROR(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown field name.");
700
0
                }
701
0
                UA_free(field_str);
702
0
                break;
703
0
            }
704
0
            default:
705
0
                break;
706
0
            }
707
0
        }
708
709
0
        if(certificate.length == 0 || privateKey.length == 0) {
710
0
            UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
711
0
                           "Certificate and PrivateKey must be set for every policy.");
712
0
            if(policy.length > 0)
713
0
                UA_String_clear(&policy);
714
0
            if(certificate.length > 0)
715
0
                UA_ByteString_clear(&certificate);
716
0
            if(privateKey.length > 0)
717
0
                UA_ByteString_clear(&privateKey);
718
0
            return UA_STATUSCODE_BADINTERNALERROR;
719
0
        }
720
0
        UA_StatusCode retval = UA_STATUSCODE_GOOD;
721
0
        if(UA_String_equal(&policy, &noneuri)) {
722
            /* Nothing to do! */
723
0
        } else if(UA_String_equal(&policy, &basic128Rsa15uri)) {
724
0
            retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &certificate, &privateKey);
725
0
            if(retval != UA_STATUSCODE_GOOD) {
726
0
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
727
0
                               "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
728
0
                               UA_StatusCode_name(retval));
729
0
            }
730
0
        } else if(UA_String_equal(&policy, &basic256uri)) {
731
0
            retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &certificate, &privateKey);
732
0
            if(retval != UA_STATUSCODE_GOOD) {
733
0
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
734
0
                               "Could not add SecurityPolicy#Basic256 with error code %s",
735
0
                               UA_StatusCode_name(retval));
736
0
            }
737
0
        } else if(UA_String_equal(&policy, &basic256Sha256uri)) {
738
0
            retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &certificate, &privateKey);
739
0
            if(retval != UA_STATUSCODE_GOOD) {
740
0
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
741
0
                               "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
742
0
                               UA_StatusCode_name(retval));
743
0
            }
744
0
        } else if(UA_String_equal(&policy, &aes128sha256rsaoaepuri)) {
745
0
            retval = UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(config, &certificate, &privateKey);
746
0
            if(retval != UA_STATUSCODE_GOOD) {
747
0
                UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
748
0
                               "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
749
0
                               UA_StatusCode_name(retval));
750
0
            }
751
0
        } else if(UA_String_equal(&policy, &aes256sha256rsapssuri)) {
752
0
             retval = UA_ServerConfig_addSecurityPolicyAes256Sha256RsaPss(config, &certificate, &privateKey);
753
0
             if(retval != UA_STATUSCODE_GOOD) {
754
0
                 UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION,
755
0
                                "Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
756
0
                               UA_StatusCode_name(retval));
757
0
            }
758
0
        } else {
759
0
            UA_LOG_WARNING(ctx->logging, UA_LOGCATEGORY_APPLICATION, "Unknown Security Policy.");
760
0
        }
761
762
        /* Add all Endpoints */
763
0
        UA_ServerConfig_addAllEndpoints(config);
764
765
0
        if(policy.length > 0)
766
0
            UA_String_clear(&policy);
767
0
        if(certificate.length > 0)
768
0
            UA_ByteString_clear(&certificate);
769
0
        if(privateKey.length > 0)
770
0
            UA_ByteString_clear(&privateKey);
771
0
    }
772
0
#endif
773
0
    return UA_STATUSCODE_GOOD;
774
0
}
775
776
0
PARSE_JSON(SecurityPkiField) {
777
0
#ifdef UA_ENABLE_ENCRYPTION
778
0
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
779
0
    UA_String pkiFolder = {.length = 0, .data = NULL};
780
781
0
    cj5_token tok = ctx->tokens[++ctx->index];
782
0
    UA_ByteString buf = getJsonPart(tok, ctx->json);
783
0
    UA_StatusCode retval = UA_decodeJson(&buf, &pkiFolder, &UA_TYPES[UA_TYPES_STRING], NULL);
784
0
    if(retval != UA_STATUSCODE_GOOD)
785
0
        return retval;
786
787
0
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)
788
    /* Currently not supported! */
789
0
    (void)config;
790
0
    return UA_STATUSCODE_GOOD;
791
#else
792
    /* Set up the parameters */
793
    UA_KeyValuePair params[2];
794
    size_t paramsSize = 2;
795
796
    params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
797
    UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);
798
    params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
799
    UA_Variant_setScalar(&params[1].value, &config->maxRejectedListSize, &UA_TYPES[UA_TYPES_UINT32]);
800
801
    UA_KeyValueMap paramsMap;
802
    paramsMap.map = params;
803
    paramsMap.mapSize = paramsSize;
804
805
    /* set server config field */
806
    UA_NodeId defaultApplicationGroup =
807
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
808
    retval = UA_CertificateGroup_Filestore(&config->secureChannelPKI, &defaultApplicationGroup,
809
                                           pkiFolder, config->logging, &paramsMap);
810
    if(retval != UA_STATUSCODE_GOOD) {
811
        UA_String_clear(&pkiFolder);
812
        return retval;
813
    }
814
815
    UA_NodeId defaultUserTokenGroup =
816
            UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
817
    retval = UA_CertificateGroup_Filestore(&config->sessionPKI, &defaultUserTokenGroup,
818
                                            pkiFolder, config->logging, &paramsMap);
819
    if(retval != UA_STATUSCODE_GOOD) {
820
        UA_String_clear(&pkiFolder);
821
        return retval;
822
    }
823
824
    /* Clean up */
825
    UA_String_clear(&pkiFolder);
826
#endif
827
0
#endif
828
0
    return UA_STATUSCODE_GOOD;
829
0
}
830
831
/*----------------------Enumerations------------------------*/
832
0
PARSE_JSON(ApplicationTypeField) {
833
0
    UA_UInt32 enum_value;
834
0
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
835
0
    if(retval != UA_STATUSCODE_GOOD)
836
0
        return retval;
837
0
    UA_ApplicationType *field = (UA_ApplicationType*)configField;
838
0
    *field = (UA_ApplicationType)enum_value;
839
0
    return retval;
840
0
}
841
0
PARSE_JSON(RuleHandlingField) {
842
0
    UA_UInt32 enum_value;
843
0
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
844
0
    if(retval != UA_STATUSCODE_GOOD)
845
0
        return retval;
846
0
    UA_RuleHandling *field = (UA_RuleHandling*)configField;
847
0
    *field = (UA_RuleHandling)enum_value;
848
0
    return retval;
849
0
}
850
851
const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS] = {
852
    /* Basic Types */
853
    (parseJsonSignature)Int64Field_parseJson,
854
    (parseJsonSignature)UInt16Field_parseJson,
855
    (parseJsonSignature)UInt32Field_parseJson,
856
    (parseJsonSignature)UInt64Field_parseJson,
857
    (parseJsonSignature)StringField_parseJson,
858
    (parseJsonSignature)LocalizedTextField_parseJson,
859
    (parseJsonSignature)DoubleField_parseJson,
860
    (parseJsonSignature)BooleanField_parseJson,
861
    (parseJsonSignature)DurationField_parseJson,
862
    (parseJsonSignature)DurationRangeField_parseJson,
863
    (parseJsonSignature)UInt32RangeField_parseJson,
864
865
    /* Advanced Types */
866
    (parseJsonSignature)BuildInfo_parseJson,
867
    (parseJsonSignature)ApplicationDescriptionField_parseJson,
868
    (parseJsonSignature)StringArrayField_parseJson,
869
    (parseJsonSignature)UInt32ArrayField_parseJson,
870
    (parseJsonSignature)DateTimeField_parseJson,
871
    (parseJsonSignature)SubscriptionConfigurationField_parseJson,
872
    (parseJsonSignature)TcpConfigurationField_parseJson,
873
    (parseJsonSignature)PubsubConfigurationField_parseJson,
874
    (parseJsonSignature)HistorizingConfigurationField_parseJson,
875
    (parseJsonSignature)MdnsConfigurationField_parseJson,
876
    (parseJsonSignature)SecurityPolciesField_parseJson,
877
    (parseJsonSignature)SecurityPkiField_parseJson,
878
879
    /* Enumerations */
880
    (parseJsonSignature)ApplicationTypeField_parseJson,
881
    (parseJsonSignature)RuleHandlingField_parseJson,
882
};
883
884
/* Skips unknown item (simple, object or array) in config file. 
885
* Unknown items may happen if we don't support some features. 
886
* E.g. if  UA_ENABLE_ENCRYPTION is not defined and config file 
887
* contains "securityPolicies" entry.
888
*/
889
static void
890
7.42k
skipUnknownItem(ParsingCtx* ctx) {
891
7.42k
    unsigned int end = ctx->tokens[ctx->index].end;
892
10.3k
    do {
893
10.3k
        ctx->index++;
894
10.3k
    } while (ctx->index < ctx->tokensSize &&
895
8.63k
        ctx->tokens[ctx->index].start < end);
896
7.42k
}
897
898
static UA_StatusCode
899
2.14k
parseJSONConfig(UA_ServerConfig *config, UA_ByteString json_config) {
900
    // Parsing json config
901
2.14k
    const char *json = (const char*)json_config.data;
902
2.14k
    cj5_token tokens[MAX_TOKENS];
903
2.14k
    cj5_result r = cj5_parse(json, (unsigned int)json_config.length, tokens, MAX_TOKENS, NULL);
904
905
    /* Validate the parse result: must succeed and produce a root object
906
     * with at least one key-value pair (i.e. >= 2 tokens). */
907
2.14k
    if(r.error != CJ5_ERROR_NONE || r.num_tokens < 2 ||
908
1.51k
       r.tokens[0].type != CJ5_TOKEN_OBJECT)
909
628
        return UA_STATUSCODE_BADDECODINGERROR;
910
911
1.51k
    ParsingCtx ctx;
912
1.51k
    ctx.json = json;
913
1.51k
    ctx.result = r;
914
1.51k
    ctx.tokens = r.tokens;
915
1.51k
    ctx.tokensSize = r.num_tokens;
916
1.51k
    ctx.index = 1; // The first token is ignored because it is known and not needed.
917
918
1.51k
    ctx.logging = config->logging;
919
920
1.51k
    size_t serverConfigSize = 0;
921
1.51k
    if(ctx.tokens)
922
1.51k
        serverConfigSize = (ctx.tokens[ctx.index-1].size/2);
923
1.51k
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
924
11.2k
    for (size_t j = serverConfigSize; j > 0; j--) {
925
9.79k
        cj5_token tok = ctx.tokens[ctx.index];
926
9.79k
        switch (tok.type) {
927
8.18k
            case CJ5_TOKEN_STRING: {
928
8.18k
                char *field = (char*)UA_malloc(tok.size + 1);
929
8.18k
                unsigned int str_len = 0;
930
8.18k
                cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
931
8.18k
                if(strcmp(field, "buildInfo") == 0)
932
19
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BUILDINFO](&ctx, &config->buildInfo, NULL);
933
8.16k
                else if(strcmp(field, "applicationDescription") == 0)
934
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION](&ctx, &config->applicationDescription, NULL);
935
8.16k
                else if(strcmp(field, "shutdownDelay") == 0)
936
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->shutdownDelay, NULL);
937
8.16k
                else if(strcmp(field, "verifyRequestTimestamp") == 0)
938
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->verifyRequestTimestamp, NULL);
939
8.16k
                else if(strcmp(field, "allowEmptyVariables") == 0)
940
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->allowEmptyVariables, NULL);
941
8.16k
                else if(strcmp(field, "serverUrls") == 0)
942
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](&ctx, &config->serverUrls, &config->serverUrlsSize);
943
8.16k
                else if(strcmp(field, "tcpEnabled") == 0)
944
1
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->tcpEnabled, NULL);
945
8.16k
                else if(strcmp(field, "tcp") == 0)
946
26
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_TCPCONFIGURATION](&ctx, config, NULL);
947
8.14k
                else if(strcmp(field, "securityPolicyNoneDiscoveryOnly") == 0)
948
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->securityPolicyNoneDiscoveryOnly, NULL);
949
8.14k
                else if(strcmp(field, "modellingRulesOnInstances") == 0)
950
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->modellingRulesOnInstances, NULL);
951
8.14k
                else if(strcmp(field, "maxSecureChannels") == 0)
952
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSecureChannels, NULL);
953
8.14k
                else if(strcmp(field, "maxSecurityTokenLifetime") == 0)
954
24
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxSecurityTokenLifetime, NULL);
955
8.11k
                else if(strcmp(field, "maxSessions") == 0)
956
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSessions, NULL);
957
8.11k
                else if(strcmp(field, "maxSessionTimeout") == 0)
958
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->maxSessionTimeout, NULL);
959
8.11k
                else if(strcmp(field, "maxNodesPerRead") == 0)
960
1
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRead, NULL);
961
8.11k
                else if(strcmp(field, "maxNodesPerWrite") == 0)
962
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerWrite, NULL);
963
8.11k
                else if(strcmp(field, "maxNodesPerMethodCall") == 0)
964
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerMethodCall, NULL);
965
8.11k
                else if(strcmp(field, "maxNodesPerBrowse") == 0)
966
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerBrowse, NULL);
967
8.11k
                else if(strcmp(field, "maxNodesPerRegisterNodes") == 0)
968
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRegisterNodes, NULL);
969
8.11k
                else if(strcmp(field, "maxNodesPerTranslateBrowsePathsToNodeIds") == 0)
970
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerTranslateBrowsePathsToNodeIds, NULL);
971
8.11k
                else if(strcmp(field, "maxNodesPerNodeManagement") == 0)
972
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerNodeManagement, NULL);
973
8.11k
                else if(strcmp(field, "maxMonitoredItemsPerCall") == 0)
974
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxMonitoredItemsPerCall, NULL);
975
8.11k
                else if(strcmp(field, "maxReferencesPerNode") == 0)
976
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxReferencesPerNode, NULL);
977
8.11k
                else if(strcmp(field, "reverseReconnectInterval") == 0)
978
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->reverseReconnectInterval, NULL);
979
980
8.11k
#if UA_MULTITHREADING >= 100
981
8.11k
                else if(strcmp(field, "asyncOperationTimeout") == 0)
982
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->asyncOperationTimeout, NULL);
983
8.11k
                else if(strcmp(field, "maxAsyncOperationQueueSize") == 0)
984
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT64](&ctx, &config->maxAsyncOperationQueueSize, NULL);
985
8.11k
#endif
986
987
8.11k
#ifdef UA_ENABLE_DISCOVERY
988
8.11k
                else if(strcmp(field, "discoveryCleanupTimeout") == 0)
989
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->discoveryCleanupTimeout, NULL);
990
8.11k
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
991
8.11k
                else if(strcmp(field, "mdnsEnabled") == 0)
992
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->mdnsEnabled, NULL);
993
8.11k
                else if(strcmp(field, "mdns") == 0)
994
685
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_MDNSCONFIGURATION](&ctx, config, NULL);
995
7.43k
#endif
996
7.43k
#endif
997
998
7.43k
#ifdef UA_ENABLE_SUBSCRIPTIONS
999
7.43k
                else if(strcmp(field, "subscriptionsEnabled") == 0)
1000
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->subscriptionsEnabled, NULL);
1001
7.43k
                else if(strcmp(field, "subscriptions") == 0)
1002
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION](&ctx, config, NULL);
1003
7.43k
# endif
1004
1005
7.43k
#ifdef UA_ENABLE_HISTORIZING
1006
7.43k
                else if(strcmp(field, "historizingEnabled") == 0)
1007
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->historizingEnabled, NULL);
1008
7.43k
                else if(strcmp(field, "historizing") == 0)
1009
1
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION](&ctx, config, NULL);
1010
7.43k
#endif
1011
1012
7.43k
#ifdef UA_ENABLE_PUBSUB
1013
7.43k
                else if(strcmp(field, "pubsubEnabled") == 0)
1014
1
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->pubsubEnabled, NULL);
1015
7.42k
                else if(strcmp(field, "pubsub") == 0)
1016
3
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION](&ctx, &config->pubSubConfig, NULL);
1017
7.42k
#endif
1018
7.42k
#ifdef UA_ENABLE_ENCRYPTION
1019
7.42k
                else if(strcmp(field, "securityPolicies") == 0)
1020
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPOLICIES](&ctx, config, NULL);
1021
7.42k
                else if(strcmp(field, "pkiFolder") == 0)
1022
0
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPKI](&ctx, config, NULL);
1023
7.42k
#endif
1024
7.42k
                else {
1025
7.42k
                    UA_LOG_WARNING(ctx.logging, UA_LOGCATEGORY_APPLICATION,
1026
7.42k
                                   "Field name '%s' unknown or misspelled. Maybe the feature is not enabled either.", field);
1027
                    /* skip the name of item */
1028
7.42k
                    ++ctx.index;
1029
                    /* skip value of unknown item */
1030
7.42k
                    skipUnknownItem(&ctx);
1031
                    /* after skipUnknownItem() ctx->index points to the name of the following item.
1032
                       We must decrement index in oder following increment will
1033
                       still set index to the right position (name of the following item) */
1034
7.42k
                    --ctx.index;
1035
7.42k
                }
1036
8.18k
                UA_free(field);
1037
8.18k
                if(retval != UA_STATUSCODE_GOOD) {
1038
26
                    UA_LOG_ERROR(ctx.logging, UA_LOGCATEGORY_APPLICATION, "An error occurred while parsing the configuration file.");
1039
26
                    return retval;
1040
26
                }
1041
8.16k
                break;
1042
8.18k
            }
1043
8.16k
            default:
1044
1.60k
                break;
1045
9.79k
        }
1046
9.77k
        ctx.index += 1;
1047
9.77k
    }
1048
1.49k
    return retval;
1049
1.51k
}
1050
1051
UA_Server *
1052
4.57k
UA_Server_newFromFile(const UA_ByteString json_config) {
1053
4.57k
    UA_ServerConfig config;
1054
4.57k
    memset(&config, 0, sizeof(UA_ServerConfig));
1055
4.57k
    UA_StatusCode res = UA_ServerConfig_setDefault(&config);
1056
4.57k
    res |= parseJSONConfig(&config, json_config);
1057
4.57k
    if(res != UA_STATUSCODE_GOOD) {
1058
1.30k
        UA_ServerConfig_clear(&config);
1059
1.30k
        return NULL;
1060
1.30k
    }
1061
3.27k
    return UA_Server_newWithConfig(&config);
1062
4.57k
}
1063
1064
UA_StatusCode
1065
0
UA_ServerConfig_updateFromFile(UA_ServerConfig *config, const UA_ByteString json_config) {
1066
0
    UA_StatusCode res = parseJSONConfig(config, json_config);
1067
0
    return res;
1068
0
}
1069
1070
#ifdef UA_ENABLE_ENCRYPTION
1071
static UA_ByteString
1072
0
loadCertificateFile(const char *const path) {
1073
0
    UA_ByteString fileContents = UA_BYTESTRING_NULL;
1074
1075
    /* Open the file */
1076
0
    FILE *fp = fopen(path, "rb");
1077
0
    if(!fp) {
1078
0
        errno = 0; /* We read errno also from the tcp layer... */
1079
0
        return fileContents;
1080
0
    }
1081
1082
    /* Get the file length, allocate the data and read */
1083
0
    if(fseek(fp, 0, SEEK_END) != 0) {
1084
0
        fclose(fp);
1085
0
        errno = 0;
1086
0
        return fileContents;
1087
0
    }
1088
1089
0
    long length = ftell(fp);
1090
0
    if(length < 0) {
1091
0
        fclose(fp);
1092
0
        errno = 0;
1093
0
        return fileContents;
1094
0
    }
1095
1096
0
    fileContents.length = (size_t)length;
1097
0
    fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
1098
0
    if(fileContents.data) {
1099
0
        if(fseek(fp, 0, SEEK_SET) != 0) {
1100
0
            fclose(fp);
1101
0
            UA_ByteString_clear(&fileContents);
1102
0
            errno = 0;
1103
0
            return fileContents;
1104
0
        }
1105
0
        size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
1106
0
        if(read != fileContents.length)
1107
0
            UA_ByteString_clear(&fileContents);
1108
0
    } else {
1109
0
        fileContents.length = 0;
1110
0
    }
1111
0
    fclose(fp);
1112
1113
0
    return fileContents;
1114
0
}
1115
#endif