open62541/plugins/ua_config_json.c

1085 lines
48 KiB
C

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
*
* Copyright 2023 (c) Fraunhofer IOSB (Author: Noel Graf)
*/
#include <open62541/server_config_file_based.h>
#include <open62541/plugin/log_stdout.h>
#include "cj5.h"
#include "open62541/server_config_default.h"
#ifdef UA_ENABLE_ENCRYPTION
#include "open62541/plugin/certificategroup_default.h"
#endif
#define MAX_TOKENS 1024
typedef struct {
const char *json;
const cj5_token *tokens;
size_t tokensSize;
size_t index;
UA_Byte depth;
cj5_result result;
} ParsingCtx;
static UA_ByteString
getJsonPart(cj5_token tok, const char *json) {
UA_ByteString bs;
UA_ByteString_init(&bs);
if(tok.type == CJ5_TOKEN_STRING) {
bs.data = (UA_Byte*)(uintptr_t)(json + tok.start - 1);
bs.length = (tok.end - tok.start) + 3;
return bs;
} else {
bs.data = (UA_Byte*)(uintptr_t)(json + tok.start);
bs.length = (tok.end - tok.start) + 1;
return bs;
}
}
/* Forward declarations*/
#define PARSE_JSON(TYPE) static UA_StatusCode \
TYPE##_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize)
typedef UA_StatusCode
(*parseJsonSignature)(ParsingCtx *ctx, void *configField, size_t *configFieldSize);
#ifdef UA_ENABLE_ENCRYPTION
static UA_ByteString
loadCertificateFile(const char *const path);
#endif
/* The DataType "kind" is an internal type classification. It is used to
* dispatch handling to the correct routines. */
#define UA_SERVERCONFIGFIELDKINDS 25
typedef enum {
/* Basic Types */
UA_SERVERCONFIGFIELD_INT64 = 0,
UA_SERVERCONFIGFIELD_UINT16,
UA_SERVERCONFIGFIELD_UINT32,
UA_SERVERCONFIGFIELD_UINT64,
UA_SERVERCONFIGFIELD_STRING,
UA_SERVERCONFIGFIELD_LOCALIZEDTEXT,
UA_SERVERCONFIGFIELD_DOUBLE,
UA_SERVERCONFIGFIELD_BOOLEAN,
UA_SERVERCONFIGFIELD_DURATION,
UA_SERVERCONFIGFIELD_DURATIONRANGE,
UA_SERVERCONFIGFIELD_UINT32RANGE,
/* Advanced Types */
UA_SERVERCONFIGFIELD_BUILDINFO,
UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION,
UA_SERVERCONFIGFIELD_STRINGARRAY,
UA_SERVERCONFIGFIELD_UINT32ARRAY,
UA_SERVERCONFIGFIELD_DATETIME,
UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION,
UA_SERVERCONFIGFIELD_TCPCONFIGURATION,
UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION,
UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION,
UA_SERVERCONFIGFIELD_MDNSCONFIGURATION,
UA_SERVERCONFIGFIELD_SECURITYPOLICIES,
UA_SERVERCONFIGFIELD_SECURITYPKI,
/* Enumerations */
UA_SERVERCONFIGFIELD_APPLICATIONTYPE,
UA_SERVERCONFIGFIELD_RULEHANDLING
} UA_ServerConfigFieldKind;
extern const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS];
/*----------------------Basic Types------------------------*/
PARSE_JSON(Int64Field) {
cj5_token tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
UA_Int64 out;
UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_INT64], NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_Int64 *field = (UA_Int64*)configField;
*field = out;
return retval;
}
PARSE_JSON(UInt16Field) {
cj5_token tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
UA_UInt16 out;
UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT16], NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_UInt16 *field = (UA_UInt16*)configField;
*field = out;
return retval;
}
PARSE_JSON(UInt32Field) {
cj5_token tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
UA_UInt32 out;
UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT32], NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_UInt32 *field = (UA_UInt32*)configField;
*field = out;
return retval;
}
PARSE_JSON(UInt64Field) {
cj5_token tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
UA_UInt64 out;
UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT64], NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_UInt64 *field = (UA_UInt64*)configField;
*field = out;
return retval;
}
PARSE_JSON(StringField) {
cj5_token tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
UA_String out;
UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_STRING], NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_String *field = (UA_String*)configField;
if(field != NULL) {
UA_String_clear(field);
*field = out;
}
return retval;
}
PARSE_JSON(LocalizedTextField) {
/*
applicationName: {
locale: "de-DE",
text: "Test text"
}
*/
cj5_token tok = ctx->tokens[++ctx->index];
UA_StatusCode retval = UA_STATUSCODE_GOOD;
UA_String locale;
UA_String text;
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field, &str_len);
tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
if(strcmp(field, "locale") == 0)
retval |= UA_decodeJson(&buf, &locale, &UA_TYPES[UA_TYPES_STRING], NULL);
else if(strcmp(field, "text") == 0)
retval |= UA_decodeJson(&buf, &text, &UA_TYPES[UA_TYPES_STRING], NULL);
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field);
break;
}
default:
break;
}
}
UA_LocalizedText out;
out.locale = locale;
out.text = text;
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_LocalizedText *field = (UA_LocalizedText*)configField;
if(field != NULL) {
UA_LocalizedText_clear(field);
*field = out;
}
return retval;
}
PARSE_JSON(DoubleField) {
cj5_token tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
UA_Double out;
UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DOUBLE], NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_Double *field = (UA_Double *)configField;
*field = out;
return retval;
}
PARSE_JSON(BooleanField) {
cj5_token tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
UA_Boolean out;
if(tok.type != CJ5_TOKEN_BOOL) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Value of type bool expected.");
return UA_STATUSCODE_BADTYPEMISMATCH;
}
UA_String val = UA_STRING("true");
if(UA_String_equal(&val, &buf)) {
out = true;
}else {
out = false;
}
/* set server config field */
UA_Boolean *field = (UA_Boolean *)configField;
*field = out;
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(DurationField) {
UA_Double double_value;
UA_StatusCode retval = DoubleField_parseJson(ctx, &double_value, NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_Duration *field = (UA_Duration*)configField;
*field = (UA_Duration)double_value;
return retval;
}
PARSE_JSON(DurationRangeField) {
UA_DurationRange *field = (UA_DurationRange*)configField;
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "min") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->min, NULL);
else if(strcmp(field_str, "max") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->max, NULL);
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(UInt32RangeField) {
UA_UInt32Range *field = (UA_UInt32Range*)configField;
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "min") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->min, NULL);
else if(strcmp(field_str, "max") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->max, NULL);
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
return UA_STATUSCODE_GOOD;
}
/*----------------------Advanced Types------------------------*/
PARSE_JSON(BuildInfo) {
UA_BuildInfo *field = (UA_BuildInfo*)configField;
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "productUri") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
else if(strcmp(field_str, "manufacturerName") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->manufacturerName, NULL);
else if(strcmp(field_str, "productName") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productName, NULL);
else if(strcmp(field_str, "softwareVersion") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->softwareVersion, NULL);
else if(strcmp(field_str, "buildNumber") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->buildNumber, NULL);
else if(strcmp(field_str, "buildDate") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_DATETIME](ctx, &field->buildDate, NULL);
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(ApplicationDescriptionField) {
UA_ApplicationDescription *field = (UA_ApplicationDescription*)configField;
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "applicationUri") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->applicationUri, NULL);
else if(strcmp(field_str, "productUri") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
else if(strcmp(field_str, "applicationName") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_LOCALIZEDTEXT](ctx, &field->applicationName, NULL);
else if(strcmp(field_str, "applicationType") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONTYPE](ctx, &field->applicationType, NULL);
else if(strcmp(field_str, "gatewayServerUri") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->gatewayServerUri, NULL);
else if(strcmp(field_str, "discoveryProfileUri") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->discoveryProfileUri, NULL);
else if(strcmp(field_str, "discoveryUrls") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &field->discoveryUrls, &field->discoveryUrlsSize);
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(StringArrayField) {
if(configFieldSize == NULL) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Pointer to the array size is not set.");
return UA_STATUSCODE_BADARGUMENTSMISSING;
}
cj5_token tok = ctx->tokens[++ctx->index];
UA_String *stringArray = (UA_String*)UA_malloc(sizeof(UA_String) * tok.size);
size_t stringArraySize = 0;
for(size_t j = tok.size; j > 0; j--) {
UA_String out = {.length = 0, .data = NULL};;
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
UA_String_copy(&out, &stringArray[stringArraySize++]);
UA_String_clear(&out);
}
/* Add to the config */
UA_String **field = (UA_String**)configField;
if(*configFieldSize > 0) {
UA_Array_delete(*field, *configFieldSize,
&UA_TYPES[UA_TYPES_STRING]);
*field = NULL;
*configFieldSize = 0;
}
UA_StatusCode retval =
UA_Array_copy(stringArray, stringArraySize,
(void**)field, &UA_TYPES[UA_TYPES_STRING]);
*configFieldSize = stringArraySize;
/* Clean up */
UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
return retval;
}
PARSE_JSON(UInt32ArrayField) {
if(configFieldSize == NULL) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Pointer to the array size is not set.");
return UA_STATUSCODE_BADARGUMENTSMISSING;
}
cj5_token tok = ctx->tokens[++ctx->index];
UA_UInt32 *numberArray = (UA_UInt32*)UA_malloc(sizeof(UA_UInt32) * tok.size);;
size_t numberArraySize = 0;
for(size_t j = tok.size; j > 0; j--) {
UA_UInt32 value;
UA_StatusCode retval = UInt32Field_parseJson(ctx, &value, NULL);
if(retval != UA_STATUSCODE_GOOD)
continue;
numberArray[numberArraySize++] = value;
}
/* Add to the config */
UA_UInt32 **field = (UA_UInt32**)configField;
if(*configFieldSize > 0) {
UA_Array_delete(*field, *configFieldSize,
&UA_TYPES[UA_TYPES_UINT32]);
*field = NULL;
*configFieldSize = 0;
}
UA_StatusCode retval = UA_STATUSCODE_GOOD;
if(numberArraySize > 0) {
retval = UA_Array_copy(numberArray, numberArraySize,
(void **)field, &UA_TYPES[UA_TYPES_UINT32]);
*configFieldSize = numberArraySize;
}
/* Clean up */
UA_Array_delete(numberArray, numberArraySize, &UA_TYPES[UA_TYPES_UINT32]);
return retval;
}
PARSE_JSON(DateTimeField) {
cj5_token tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
UA_DateTime out;
UA_DateTime_init(&out);
UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DATETIME], NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_DateTime *field = (UA_DateTime*)configField;
*field = out;
return retval;
}
PARSE_JSON(MdnsConfigurationField) {
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
UA_ServerConfig *config = (UA_ServerConfig*)configField;
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "mdnsServerName") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsConfig.mdnsServerName, NULL);
else if(strcmp(field_str, "serverCapabilities") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &config->mdnsConfig.serverCapabilities, &config->mdnsConfig.serverCapabilitiesSize);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST_MDNSD
else if(strcmp(field_str, "mdnsInterfaceIP") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsInterfaceIP, NULL);
/* mdnsIpAddressList and mdnsIpAddressListSize are only available if UA_HAS_GETIFADDR is not defined: */
# if !defined(UA_HAS_GETIFADDR)
else if(strcmp(field_str, "mdnsIpAddressList") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32ARRAY](ctx, &config->mdnsIpAddressList, &config->mdnsIpAddressListSize);
# endif
#endif
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
#endif
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(SubscriptionConfigurationField) {
#ifdef UA_ENABLE_SUBSCRIPTIONS
UA_ServerConfig *config = (UA_ServerConfig*)configField;
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "maxSubscriptions") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptions, NULL);
else if(strcmp(field_str, "maxSubscriptionsPerSession") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptionsPerSession, NULL);
else if(strcmp(field_str, "publishingIntervalLimits") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->publishingIntervalLimits, NULL);
else if(strcmp(field_str, "lifeTimeCountLimits") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->lifeTimeCountLimits, NULL);
else if(strcmp(field_str, "keepAliveCountLimits") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->keepAliveCountLimits, NULL);
else if(strcmp(field_str, "maxNotificationsPerPublish") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxNotificationsPerPublish, NULL);
else if(strcmp(field_str, "enableRetransmissionQueue") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->enableRetransmissionQueue, NULL);
else if(strcmp(field_str, "maxRetransmissionQueueSize") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxRetransmissionQueueSize, NULL);
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
else if(strcmp(field_str, "maxEventsPerNode") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxEventsPerNode, NULL);
# endif
else if(strcmp(field_str, "maxMonitoredItems") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItems, NULL);
else if(strcmp(field_str, "maxMonitoredItemsPerSubscription") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItemsPerSubscription, NULL);
else if(strcmp(field_str, "samplingIntervalLimits") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->samplingIntervalLimits, NULL);
else if(strcmp(field_str, "queueSizeLimits") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->queueSizeLimits, NULL);
else if(strcmp(field_str, "maxPublishReqPerSession") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxPublishReqPerSession, NULL);
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
#endif
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(TcpConfigurationField) {
UA_ServerConfig *config = (UA_ServerConfig*)configField;
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "tcpBufSize") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpBufSize, NULL);
else if(strcmp(field_str, "tcpMaxMsgSize") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxMsgSize, NULL);
else if(strcmp(field_str, "tcpMaxChunks") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxChunks, NULL);
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(PubsubConfigurationField) {
#ifdef UA_ENABLE_PUBSUB
UA_PubSubConfiguration *field = (UA_PubSubConfiguration*)configField;
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "enableDeltaFrames") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableDeltaFrames, NULL);
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
else if(strcmp(field_str, "enableInformationModelMethods") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableInformationModelMethods, NULL);
#endif
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
#endif
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(HistorizingConfigurationField) {
#ifdef UA_ENABLE_HISTORIZING
UA_ServerConfig *config = (UA_ServerConfig*)configField;
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size/2; j > 0; j--) {
tok = ctx->tokens[++ctx->index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "accessHistoryDataCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryDataCapability, NULL);
else if(strcmp(field_str, "maxReturnDataValues") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnDataValues, NULL);
else if(strcmp(field_str, "accessHistoryEventsCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryEventsCapability, NULL);
else if(strcmp(field_str, "maxReturnEventValues") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnEventValues, NULL);
else if(strcmp(field_str, "insertDataCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertDataCapability, NULL);
else if(strcmp(field_str, "insertEventCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertEventCapability, NULL);
else if(strcmp(field_str, "insertAnnotationsCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertAnnotationsCapability, NULL);
else if(strcmp(field_str, "replaceDataCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceDataCapability, NULL);
else if(strcmp(field_str, "replaceEventCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceEventCapability, NULL);
else if(strcmp(field_str, "updateDataCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateDataCapability, NULL);
else if(strcmp(field_str, "updateEventCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateEventCapability, NULL);
else if(strcmp(field_str, "deleteRawCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteRawCapability, NULL);
else if(strcmp(field_str, "deleteEventCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteEventCapability, NULL);
else if(strcmp(field_str, "deleteAtTimeDataCapability") == 0)
parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteAtTimeDataCapability, NULL);
else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
#endif
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(SecurityPolciesField) {
#ifdef UA_ENABLE_ENCRYPTION
UA_ServerConfig *config = (UA_ServerConfig*)configField;
UA_String noneuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
UA_String basic128Rsa15uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
UA_String basic256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
UA_String basic256Sha256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
UA_String aes128sha256rsaoaepuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
UA_String aes256sha256rsapssuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
cj5_token tok = ctx->tokens[++ctx->index];
for(size_t j = tok.size; j > 0; j--) {
UA_String policy = {.length = 0, .data = NULL};
UA_ByteString certificate = {.length = 0, .data = NULL};
UA_ByteString privateKey = {.length = 0, .data = NULL};
tok = ctx->tokens[++ctx->index];
for(size_t i = tok.size / 2; i > 0; i--) {
tok = ctx->tokens[++ctx->index];
switch(tok.type) {
case CJ5_TOKEN_STRING: {
char *field_str = (char *)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
if(strcmp(field_str, "certificate") == 0) {
UA_String out = {.length = 0, .data = NULL};
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
if(out.length > 0) {
char *certfile = (char *)UA_malloc(out.length + 1);
memcpy(certfile, out.data, out.length);
certfile[out.length] = '\0';
certificate = loadCertificateFile(certfile);
UA_String_clear(&out);
UA_free(certfile);
}
} else if(strcmp(field_str, "privateKey") == 0) {
UA_String out = {.length = 0, .data = NULL};
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
if(out.length > 0) {
char *keyfile = (char *)UA_malloc(out.length + 1);
memcpy(keyfile, out.data, out.length);
keyfile[out.length] = '\0';
privateKey = loadCertificateFile(keyfile);
UA_String_clear(&out);
UA_free(keyfile);
}
} else if(strcmp(field_str, "policy") == 0) {
parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &policy, NULL);
} else {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
}
UA_free(field_str);
break;
}
default:
break;
}
}
if(certificate.length == 0 || privateKey.length == 0) {
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
"Certificate and PrivateKey must be set for every policy.");
if(policy.length > 0)
UA_String_clear(&policy);
if(certificate.length > 0)
UA_ByteString_clear(&certificate);
if(privateKey.length > 0)
UA_ByteString_clear(&privateKey);
return UA_STATUSCODE_BADINTERNALERROR;
}
UA_StatusCode retval = UA_STATUSCODE_GOOD;
if(UA_String_equal(&policy, &noneuri)) {
/* Nothing to do! */
} else if(UA_String_equal(&policy, &basic128Rsa15uri)) {
retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &certificate, &privateKey);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
"Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
UA_StatusCode_name(retval));
}
} else if(UA_String_equal(&policy, &basic256uri)) {
retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &certificate, &privateKey);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
"Could not add SecurityPolicy#Basic256 with error code %s",
UA_StatusCode_name(retval));
}
} else if(UA_String_equal(&policy, &basic256Sha256uri)) {
retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &certificate, &privateKey);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
"Could not add SecurityPolicy#Basic256Sha256 with error code %s",
UA_StatusCode_name(retval));
}
} else if(UA_String_equal(&policy, &aes128sha256rsaoaepuri)) {
retval = UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(config, &certificate, &privateKey);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
"Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
UA_StatusCode_name(retval));
}
} else if(UA_String_equal(&policy, &aes256sha256rsapssuri)) {
retval = UA_ServerConfig_addSecurityPolicyAes256Sha256RsaPss(config, &certificate, &privateKey);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
"Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
UA_StatusCode_name(retval));
}
} else {
UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND, "Unknown Security Policy.");
}
/* Add all Endpoints */
UA_ServerConfig_addAllEndpoints(config);
if(policy.length > 0)
UA_String_clear(&policy);
if(certificate.length > 0)
UA_ByteString_clear(&certificate);
if(privateKey.length > 0)
UA_ByteString_clear(&privateKey);
}
#endif
return UA_STATUSCODE_GOOD;
}
PARSE_JSON(SecurityPkiField) {
#ifdef UA_ENABLE_ENCRYPTION
UA_ServerConfig *config = (UA_ServerConfig*)configField;
UA_String pkiFolder = {.length = 0, .data = NULL};
cj5_token tok = ctx->tokens[++ctx->index];
UA_ByteString buf = getJsonPart(tok, ctx->json);
UA_StatusCode retval = UA_decodeJson(&buf, &pkiFolder, &UA_TYPES[UA_TYPES_STRING], NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)
/* Currently not supported! */
(void)config;
return UA_STATUSCODE_GOOD;
#else
/* Set up the parameters */
UA_KeyValuePair params[2];
size_t paramsSize = 2;
params[0].key = UA_QUALIFIEDNAME(0, "max-trust-listsize");
UA_Variant_setScalar(&params[0].value, &config->maxTrustListSize, &UA_TYPES[UA_TYPES_UINT32]);
params[1].key = UA_QUALIFIEDNAME(0, "max-rejected-listsize");
UA_Variant_setScalar(&params[1].value, &config->maxRejectedListSize, &UA_TYPES[UA_TYPES_UINT32]);
UA_KeyValueMap paramsMap;
paramsMap.map = params;
paramsMap.mapSize = paramsSize;
/* set server config field */
UA_NodeId defaultApplicationGroup =
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
retval = UA_CertificateGroup_Filestore(&config->secureChannelPKI, &defaultApplicationGroup,
pkiFolder, config->logging, &paramsMap);
if(retval != UA_STATUSCODE_GOOD) {
UA_String_clear(&pkiFolder);
return retval;
}
UA_NodeId defaultUserTokenGroup =
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP);
retval = UA_CertificateGroup_Filestore(&config->sessionPKI, &defaultUserTokenGroup,
pkiFolder, config->logging, &paramsMap);
if(retval != UA_STATUSCODE_GOOD) {
UA_String_clear(&pkiFolder);
return retval;
}
/* Clean up */
UA_String_clear(&pkiFolder);
#endif
#endif
return UA_STATUSCODE_GOOD;
}
/*----------------------Enumerations------------------------*/
PARSE_JSON(ApplicationTypeField) {
UA_UInt32 enum_value;
UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_ApplicationType *field = (UA_ApplicationType*)configField;
*field = (UA_ApplicationType)enum_value;
return retval;
}
PARSE_JSON(RuleHandlingField) {
UA_UInt32 enum_value;
UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
if(retval != UA_STATUSCODE_GOOD)
return retval;
UA_RuleHandling *field = (UA_RuleHandling*)configField;
*field = (UA_RuleHandling)enum_value;
return retval;
}
const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS] = {
/* Basic Types */
(parseJsonSignature)Int64Field_parseJson,
(parseJsonSignature)UInt16Field_parseJson,
(parseJsonSignature)UInt32Field_parseJson,
(parseJsonSignature)UInt64Field_parseJson,
(parseJsonSignature)StringField_parseJson,
(parseJsonSignature)LocalizedTextField_parseJson,
(parseJsonSignature)DoubleField_parseJson,
(parseJsonSignature)BooleanField_parseJson,
(parseJsonSignature)DurationField_parseJson,
(parseJsonSignature)DurationRangeField_parseJson,
(parseJsonSignature)UInt32RangeField_parseJson,
/* Advanced Types */
(parseJsonSignature)BuildInfo_parseJson,
(parseJsonSignature)ApplicationDescriptionField_parseJson,
(parseJsonSignature)StringArrayField_parseJson,
(parseJsonSignature)UInt32ArrayField_parseJson,
(parseJsonSignature)DateTimeField_parseJson,
(parseJsonSignature)SubscriptionConfigurationField_parseJson,
(parseJsonSignature)TcpConfigurationField_parseJson,
(parseJsonSignature)PubsubConfigurationField_parseJson,
(parseJsonSignature)HistorizingConfigurationField_parseJson,
(parseJsonSignature)MdnsConfigurationField_parseJson,
(parseJsonSignature)SecurityPolciesField_parseJson,
(parseJsonSignature)SecurityPkiField_parseJson,
/* Enumerations */
(parseJsonSignature)ApplicationTypeField_parseJson,
(parseJsonSignature)RuleHandlingField_parseJson,
};
/* Skips unknown item (simple, object or array) in config file.
* Unknown items may happen if we don't support some features.
* E.g. if UA_ENABLE_ENCRYPTION is not defined and config file
* contains "securityPolicies" entry.
*/
static void
skipUnknownItem(ParsingCtx* ctx) {
unsigned int end = ctx->tokens[ctx->index].end;
do {
ctx->index++;
} while (ctx->index < ctx->tokensSize &&
ctx->tokens[ctx->index].start < end);
}
static UA_StatusCode
parseJSONConfig(UA_ServerConfig *config, UA_ByteString json_config) {
// Parsing json config
const char *json = (const char*)json_config.data;
cj5_token tokens[MAX_TOKENS];
cj5_result r = cj5_parse(json, (unsigned int)json_config.length, tokens, MAX_TOKENS, NULL);
ParsingCtx ctx;
ctx.json = json;
ctx.result = r;
ctx.tokens = r.tokens;
ctx.tokensSize = r.num_tokens;
ctx.index = 1; // The first token is ignored because it is known and not needed.
size_t serverConfigSize = 0;
if(ctx.tokens)
serverConfigSize = (ctx.tokens[ctx.index-1].size/2);
UA_StatusCode retval = UA_STATUSCODE_GOOD;
for (size_t j = serverConfigSize; j > 0; j--) {
cj5_token tok = ctx.tokens[ctx.index];
switch (tok.type) {
case CJ5_TOKEN_STRING: {
char *field = (char*)UA_malloc(tok.size + 1);
unsigned int str_len = 0;
cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
if(strcmp(field, "buildInfo") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BUILDINFO](&ctx, &config->buildInfo, NULL);
else if(strcmp(field, "applicationDescription") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION](&ctx, &config->applicationDescription, NULL);
else if(strcmp(field, "shutdownDelay") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->shutdownDelay, NULL);
else if(strcmp(field, "verifyRequestTimestamp") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->verifyRequestTimestamp, NULL);
else if(strcmp(field, "allowEmptyVariables") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->allowEmptyVariables, NULL);
else if(strcmp(field, "serverUrls") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](&ctx, &config->serverUrls, &config->serverUrlsSize);
else if(strcmp(field, "tcpEnabled") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->tcpEnabled, NULL);
else if(strcmp(field, "tcp") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_TCPCONFIGURATION](&ctx, config, NULL);
else if(strcmp(field, "securityPolicyNoneDiscoveryOnly") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->securityPolicyNoneDiscoveryOnly, NULL);
else if(strcmp(field, "modellingRulesOnInstances") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->modellingRulesOnInstances, NULL);
else if(strcmp(field, "maxSecureChannels") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSecureChannels, NULL);
else if(strcmp(field, "maxSecurityTokenLifetime") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxSecurityTokenLifetime, NULL);
else if(strcmp(field, "maxSessions") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSessions, NULL);
else if(strcmp(field, "maxSessionTimeout") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->maxSessionTimeout, NULL);
else if(strcmp(field, "maxNodesPerRead") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRead, NULL);
else if(strcmp(field, "maxNodesPerWrite") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerWrite, NULL);
else if(strcmp(field, "maxNodesPerMethodCall") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerMethodCall, NULL);
else if(strcmp(field, "maxNodesPerBrowse") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerBrowse, NULL);
else if(strcmp(field, "maxNodesPerRegisterNodes") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRegisterNodes, NULL);
else if(strcmp(field, "maxNodesPerTranslateBrowsePathsToNodeIds") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerTranslateBrowsePathsToNodeIds, NULL);
else if(strcmp(field, "maxNodesPerNodeManagement") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerNodeManagement, NULL);
else if(strcmp(field, "maxMonitoredItemsPerCall") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxMonitoredItemsPerCall, NULL);
else if(strcmp(field, "maxReferencesPerNode") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxReferencesPerNode, NULL);
else if(strcmp(field, "reverseReconnectInterval") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->reverseReconnectInterval, NULL);
#if UA_MULTITHREADING >= 100
else if(strcmp(field, "asyncOperationTimeout") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->asyncOperationTimeout, NULL);
else if(strcmp(field, "maxAsyncOperationQueueSize") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT64](&ctx, &config->maxAsyncOperationQueueSize, NULL);
#endif
#ifdef UA_ENABLE_DISCOVERY
else if(strcmp(field, "discoveryCleanupTimeout") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->discoveryCleanupTimeout, NULL);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
else if(strcmp(field, "mdnsEnabled") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->mdnsEnabled, NULL);
else if(strcmp(field, "mdns") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_MDNSCONFIGURATION](&ctx, config, NULL);
#endif
#endif
#ifdef UA_ENABLE_SUBSCRIPTIONS
else if(strcmp(field, "subscriptionsEnabled") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->subscriptionsEnabled, NULL);
else if(strcmp(field, "subscriptions") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION](&ctx, config, NULL);
# endif
#ifdef UA_ENABLE_HISTORIZING
else if(strcmp(field, "historizingEnabled") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->historizingEnabled, NULL);
else if(strcmp(field, "historizing") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION](&ctx, config, NULL);
#endif
#ifdef UA_ENABLE_PUBSUB
else if(strcmp(field, "pubsubEnabled") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->pubsubEnabled, NULL);
else if(strcmp(field, "pubsub") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION](&ctx, &config->pubSubConfig, NULL);
#endif
#ifdef UA_ENABLE_ENCRYPTION
else if(strcmp(field, "securityPolicies") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPOLICIES](&ctx, config, NULL);
else if(strcmp(field, "pkiFolder") == 0)
retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPKI](&ctx, config, NULL);
#endif
else {
UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Field name '%s' unknown or misspelled. Maybe the feature is not enabled either.", field);
/* skip the name of item */
++ctx.index;
/* skip value of unknown item */
skipUnknownItem(&ctx);
/* after skipUnknownItem() ctx->index points to the name of the following item.
We must decrement index in oder following increment will
still set index to the right position (name of the following item) */
--ctx.index;
}
UA_free(field);
if(retval != UA_STATUSCODE_GOOD) {
UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "An error occurred while parsing the configuration file.");
return retval;
}
break;
}
default:
break;
}
ctx.index += 1;
}
return retval;
}
UA_Server *
UA_Server_newFromFile(const UA_ByteString json_config) {
UA_ServerConfig config;
memset(&config, 0, sizeof(UA_ServerConfig));
UA_StatusCode res = UA_ServerConfig_setDefault(&config);
res |= parseJSONConfig(&config, json_config);
if(res != UA_STATUSCODE_GOOD)
return NULL;
return UA_Server_newWithConfig(&config);
}
UA_StatusCode
UA_ServerConfig_updateFromFile(UA_ServerConfig *config, const UA_ByteString json_config) {
UA_StatusCode res = parseJSONConfig(config, json_config);
return res;
}
#ifdef UA_ENABLE_ENCRYPTION
static UA_ByteString
loadCertificateFile(const char *const path) {
UA_ByteString fileContents = UA_BYTESTRING_NULL;
/* Open the file */
FILE *fp = fopen(path, "rb");
if(!fp) {
errno = 0; /* We read errno also from the tcp layer... */
return fileContents;
}
/* Get the file length, allocate the data and read */
fseek(fp, 0, SEEK_END);
fileContents.length = (size_t)ftell(fp);
fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
if(fileContents.data) {
fseek(fp, 0, SEEK_SET);
size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
if(read != fileContents.length)
UA_ByteString_clear(&fileContents);
} else {
fileContents.length = 0;
}
fclose(fp);
return fileContents;
}
#endif