Coverage Report

Created: 2025-08-29 06:10

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