diff --git a/include/open62541/types.h b/include/open62541/types.h index e48e0a44a..a1e5828ca 100644 --- a/include/open62541/types.h +++ b/include/open62541/types.h @@ -1103,7 +1103,7 @@ typedef struct UA_DataTypeArray { * If the member is an array, the offset points to the (size_t) length field. * (The array pointer comes after the length field without any padding.) */ #ifdef UA_ENABLE_TYPEDESCRIPTION -UA_Boolean +UA_Boolean UA_EXPORT UA_DataType_getStructMember(const UA_DataType *type, const char *memberName, size_t *outOffset, @@ -1114,7 +1114,7 @@ UA_DataType_getStructMember(const UA_DataType *type, /* Test if the data type is a numeric builtin data type (via the typeKind field * of UA_DataType). This includes integers and floating point numbers. Not * included are Boolean, DateTime, StatusCode and Enums. */ -UA_Boolean +UA_Boolean UA_EXPORT UA_DataType_isNumeric(const UA_DataType *type); /** diff --git a/plugins/crypto/openssl/certificategroup.c b/plugins/crypto/openssl/certificategroup.c index e5e83cf59..ac4b5e956 100644 --- a/plugins/crypto/openssl/certificategroup.c +++ b/plugins/crypto/openssl/certificategroup.c @@ -407,6 +407,8 @@ verifyCertificate(UA_CertificateGroup *certGroup, const UA_ByteString *certifica opensslRet = X509_STORE_CTX_get_error(storeCtx); if(opensslRet == X509_V_ERR_UNABLE_TO_GET_CRL) { ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN; + } else { + ret = UA_X509_Store_CTX_Error_To_UAError (opensslRet); } } } diff --git a/plugins/ua_config_default.c b/plugins/ua_config_default.c index 6e3100e68..12fdea0b1 100644 --- a/plugins/ua_config_default.c +++ b/plugins/ua_config_default.c @@ -443,7 +443,7 @@ setDefaultConfig(UA_ServerConfig *conf, UA_UInt16 portNumber) { conf->modellingRulesOnInstances = true; /* Limits for SecureChannels */ - conf->maxSecureChannels = 40; + conf->maxSecureChannels = 100; conf->maxSecurityTokenLifetime = 10 * 60 * 1000; /* 10 minutes */ /* Limits for Sessions */ diff --git a/src/client/ua_client_highlevel.c b/src/client/ua_client_highlevel.c index 0d9b57e92..883e0ade4 100644 --- a/src/client/ua_client_highlevel.c +++ b/src/client/ua_client_highlevel.c @@ -882,7 +882,12 @@ AttributeReadCallback(UA_Client *client, void *userdata, /* Check the type. Try to adjust "in situ" if no match. */ if(!UA_Variant_hasScalarType(&dv->value, ctx->resultType)) { + /* Remember the old pointer, adjustType can "unwrap" a type but won't + * free the wrapper. Because the server code still keeps the wrapper. */ + void *oldVal = dv->value.data; adjustType(&dv->value, ctx->resultType); + if(dv->value.data != oldVal) + UA_free(oldVal); if(!UA_Variant_hasScalarType(&dv->value, ctx->resultType)) { res = UA_STATUSCODE_BADINTERNALERROR; goto finish; diff --git a/src/server/ua_server.c b/src/server/ua_server.c index 25e0b5724..a9e3d081d 100644 --- a/src/server/ua_server.c +++ b/src/server/ua_server.c @@ -796,7 +796,7 @@ UA_Server_run_startup(UA_Server *server) { /* Are there enough SecureChannels possible for the max number of sessions? */ if(config->maxSecureChannels != 0 && - (config->maxSessions == 0 || config->maxSessions >= config->maxSecureChannels)) { + (config->maxSessions == 0 || config->maxSessions > config->maxSecureChannels)) { UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER, "Maximum SecureChannels count not enough for the " "maximum Sessions count"); @@ -810,6 +810,7 @@ UA_Server_run_startup(UA_Server *server) { "Could not create the server housekeeping task"); /* Ensure that the uri for ns1 is set up from the app description */ + UA_String_clear(&server->namespaces[1]); setupNs1Uri(server); /* At least one endpoint has to be configured */ diff --git a/src/ua_types.c b/src/ua_types.c index 6d0b69a5d..d33c8bee7 100644 --- a/src/ua_types.c +++ b/src/ua_types.c @@ -2053,7 +2053,7 @@ UA_Array_append(void **p, size_t *size, void *newElem, return UA_STATUSCODE_GOOD; } -UA_StatusCode UA_EXPORT +UA_StatusCode UA_Array_appendCopy(void **p, size_t *size, const void *newElem, const UA_DataType *type) { char scratch[512]; diff --git a/src/util/ua_util.c b/src/util/ua_util.c index 2ad997ca3..dbbf26718 100644 --- a/src/util/ua_util.c +++ b/src/util/ua_util.c @@ -78,8 +78,6 @@ adjustType(UA_Variant *value, const UA_DataType *targetType) { value->type = &UA_TYPES[UA_TYPES_BYTE]; value->arrayLength = str->length; value->data = str->data; - if(value->storageType != UA_VARIANT_DATA_NODELETE) - UA_free(str); return; } diff --git a/src/util/ua_util_internal.h b/src/util/ua_util_internal.h index ccd5f75fd..be242f2e2 100644 --- a/src/util/ua_util_internal.h +++ b/src/util/ua_util_internal.h @@ -28,7 +28,12 @@ _UA_BEGIN_DECLS #define UA_MACRO_EXPAND(x) x /* Try if the type of the value can be adjusted "in situ" to the target type. - * That can be done, for example, to map between int32 and an enum. */ + * That can be done, for example, to map between int32 and an enum. + * + * This can also "unwrap" a type. For example: string -> array of bytes + * + * If value->data is changed during adjustType, free the pointer afterwards (if + * you did not keep the original variant for _clear). */ void adjustType(UA_Variant *value, const UA_DataType *targetType); diff --git a/tests/server/check_server_userspace.c b/tests/server/check_server_userspace.c index a7b7883be..039325a9f 100644 --- a/tests/server/check_server_userspace.c +++ b/tests/server/check_server_userspace.c @@ -15,6 +15,27 @@ #pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers" #endif +START_TEST(Server_Namespace1_check) { + UA_Server *server = UA_Server_new(); + UA_ServerConfig *config = UA_Server_getConfig(server); + + const char *namespace1 = "http://namespace1"; + UA_String_clear(&config->applicationDescription.applicationUri); + config->applicationDescription.applicationUri = UA_STRING_ALLOC(namespace1); + + UA_Server_run_startup(server); + + UA_String out; + UA_StatusCode status = UA_Server_getNamespaceByIndex(server, 1, &out); + ck_assert(status == UA_STATUSCODE_GOOD); + + ck_assert(UA_String_equal(&out, &config->applicationDescription.applicationUri)); + UA_String_clear(&out); + UA_Server_run_shutdown(server); + UA_Server_delete(server); +} +END_TEST + START_TEST(Server_addNamespace_ShallWork) { UA_Server *server = UA_Server_newForUnitTest(); @@ -185,6 +206,7 @@ START_TEST(Server_forEachChildNodeCall) { static Suite* testSuite_ServerUserspace(void) { Suite *s = suite_create("ServerUserspace"); TCase *tc_core = tcase_create("Core"); + tcase_add_test(tc_core, Server_Namespace1_check); tcase_add_test(tc_core, Server_addNamespace_ShallWork); tcase_add_test(tc_core, Server_addNamespace_writeService); tcase_add_test(tc_core, Server_forEachChildNodeCall); diff --git a/tests/server/check_services_attributes.c b/tests/server/check_services_attributes.c index a2d143e2e..0a22b110d 100644 --- a/tests/server/check_services_attributes.c +++ b/tests/server/check_services_attributes.c @@ -894,6 +894,58 @@ START_TEST(WriteSingleAttributeValueEnum) { UA_DataValue_clear(&resp); } END_TEST +/* Writing a ByteString into a byte array */ +START_TEST(WriteSingleAttributeStringToByteArray) { + UA_WriteValue wValue; + UA_WriteValue_init(&wValue); + + UA_VariableAttributes vattr = UA_VariableAttributes_default; + UA_Byte testArray[4] = {1,2,3,4}; + UA_UInt32 testArrayDims[1] = {4}; + UA_Variant_setArray(&vattr.value, testArray, 4, &UA_TYPES[UA_TYPES_BYTE]); + vattr.value.arrayDimensions = testArrayDims; + vattr.value.arrayDimensionsSize = 1; + vattr.description = UA_LOCALIZEDTEXT("locale","test array"); + vattr.displayName = UA_LOCALIZEDTEXT("locale","test array"); + vattr.valueRank = UA_VALUERANK_ONE_DIMENSION; + vattr.arrayDimensions = testArrayDims; + vattr.arrayDimensionsSize = 1; + vattr.dataType = UA_TYPES[UA_TYPES_BYTE].typeId; + UA_QualifiedName arrayName = UA_QUALIFIEDNAME(1, "test array"); + UA_NodeId arrayNodeId = UA_NODEID_STRING(1, "test.array"); + UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); + UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES); + UA_StatusCode retval = + UA_Server_addVariableNode(server, arrayNodeId, parentNodeId, + parentReferenceNodeId, arrayName, + UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), + vattr, NULL, NULL); + ck_assert_int_eq(retval, UA_STATUSCODE_GOOD); + + UA_String testString = UA_STRING("open"); + UA_Variant_setScalar(&wValue.value.value, &testString, &UA_TYPES[UA_TYPES_BYTESTRING]); + wValue.value.hasValue = true; + wValue.nodeId = UA_NODEID_STRING(1, "test.array"); + wValue.attributeId = UA_ATTRIBUTEID_VALUE; + retval = UA_Server_write(server, &wValue); + ck_assert_int_eq(retval, UA_STATUSCODE_GOOD); + + UA_ReadValueId rvi; + UA_ReadValueId_init(&rvi); + rvi.nodeId = UA_NODEID_STRING(1, "test.array"); + rvi.attributeId = UA_ATTRIBUTEID_VALUE; + UA_DataValue resp = UA_Server_read(server, &rvi, UA_TIMESTAMPSTORETURN_NEITHER); + ck_assert_int_eq(resp.status, UA_STATUSCODE_GOOD); + ck_assert(resp.hasValue); + ck_assert(UA_Variant_hasArrayType(&resp.value, &UA_TYPES[UA_TYPES_BYTE])); + + UA_Byte *arr = (UA_Byte*)resp.value.data; + arr[0] = 'o'; + arr[1] = 'p'; + + UA_DataValue_clear(&resp); +} END_TEST + START_TEST(WriteSingleAttributeValueRangeFromScalar) { UA_WriteValue wValue; UA_WriteValue_init(&wValue); @@ -1179,6 +1231,7 @@ static Suite * testSuite_services_attributes(void) { tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeValue); tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeValueWithServerTimestamp); tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeValueEnum); + tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeStringToByteArray); tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeDataType); tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeValueRangeFromScalar); tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeValueRangeFromArray);