X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=ntsimulator%2Fntsim-ng%2Futils%2Frand_utils.c;fp=ntsimulator%2Fntsim-ng%2Futils%2Frand_utils.c;h=28222e698e0f33a010260a5c7e707ca3e8891db5;hb=f1d5c9198acde7a7ce296490087cad37e008f688;hp=0000000000000000000000000000000000000000;hpb=f2d8f1002fa93848c80a88e5658db4816cba3020;p=sim%2Fo1-interface.git diff --git a/ntsimulator/ntsim-ng/utils/rand_utils.c b/ntsimulator/ntsim-ng/utils/rand_utils.c new file mode 100644 index 0000000..28222e6 --- /dev/null +++ b/ntsimulator/ntsim-ng/utils/rand_utils.c @@ -0,0 +1,920 @@ +/************************************************************************* +* +* Copyright 2020 highstreet technologies GmbH and others +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +***************************************************************************/ + +#define _GNU_SOURCE + +#include "rand_utils.h" +#include "log_utils.h" +#include "sys_utils.h" //for b64_encode +#include +#include +#include +#include +#include +#include + +#include "core/context.h" //for context_get_identity_leafs_of_type +#include "core/framework.h" //to check for no_rand + +//private definitions +typedef struct __rand_range { + union { + int64_t num; + double dec; + } value; + + union { + int64_t num; + double dec; + } min; + + union { + int64_t num; + double dec; + } max; +} rand_range_t; + +//private functions +static char *rand_string(int min_length, int max_length); +static struct lys_ident *rand_identity(struct lys_ident *type); + +//random based on ranges +static int64_t rand_range_type_int_min(LY_DATA_TYPE type); +static int64_t rand_range_type_int_max(LY_DATA_TYPE type); +static rand_range_t rand_range(const char *range, const LY_DATA_TYPE type); + +//for the following functions, the result should be freed by the user +static char *rand_date_and_time(void); +static char *rand_ipv4_address(void); +static char *rand_ipv6_address(void); +static char *rand_uuid(void); + + +void rand_init(void) { + unsigned int seed; + + FILE* urandom = fopen("/dev/urandom", "r"); + if(urandom == 0) { + log_error("failed to open /dev/urandom"); + } + else { + fread(&seed, sizeof(int), 1, urandom); + fclose(urandom); + } + + srand(seed); + srandom(seed); + + log_message(2, "rand_init() was called and seed was initialized to %u\n", seed); + if(RAND_MAX < 65536) { + log_error("RAND_MAX is too low: %d", RAND_MAX); + } +} + +void rand_init_fixed(unsigned int seed) { + srand(seed); + srandom(seed); + + log_message(2, "rand_init_fixed() was called and seed was initialized to %u\n", seed); + + if(RAND_MAX < 65536) { + log_error("RAND_MAX is too low: %d", RAND_MAX); + } +} + +char *rand_get_populate_value(const struct lys_type *type) { + assert(type); + + char *ret = 0; + + if(type->der->module) { + char *full_type = 0; + + asprintf(&full_type, "%s:%s", type->der->module->name, type->der->name); + if(full_type == 0) { + log_error("bad malloc"); + return 0; + } + + if(strstr(full_type, "ietf-yang-types:date-and-time") != 0) { + ret = rand_date_and_time(); + } + else if(strstr(full_type, "ietf-inet-types:ipv4-address") != 0) { + ret = rand_ipv4_address(); + } + else if(strstr(full_type, "ietf-inet-types:ipv6-address") != 0) { + ret = rand_ipv6_address(); + } + else if((strstr(full_type, "ietf-yang-types:mac-address") != 0) || (strstr(full_type, "ietf-yang-types:phys-address") != 0)) { + ret = rand_mac_address(); + } + else if(strstr(full_type, "universal-id") != 0) { + ret = rand_uuid(); + } + + free(full_type); + if(ret) { + return ret; + } + } + + switch(type->base) { + case LY_TYPE_EMPTY: + case LY_TYPE_BOOL: + if(rand_bool()) { + asprintf(&ret, "true"); + return ret; + } + else { + asprintf(&ret, "false"); + return ret; + } + break; + + case LY_TYPE_DER: + return rand_get_populate_value(&type->der->type); + break; + + case LY_TYPE_ENUM: + if(type->info.enums.count) { + int i = rand_uint16() % type->info.enums.count; + asprintf(&ret, "%s", type->info.enums.enm[i].name); + return ret; + } + else { + return rand_get_populate_value(&type->der->type); + } + break; + + case LY_TYPE_IDENT: { + while(!type->info.ident.ref) { + type = &type->der->type; + } + struct lys_ident *ident = rand_identity(type->info.ident.ref[0]); + if(ident == 0) { + log_error("rand_identity failed"); + return 0; + } + + asprintf(&ret, "%s:%s", ident->module->name, ident->name); + return ret; + } break; + + case LY_TYPE_STRING: { + int min_length = 1; + int max_length = 255; + char *expression = 0; + bool found_length = false; + + do { + if(type->info.str.length && !found_length) { + rand_range_t vals = rand_range(type->info.str.length->expr, LY_TYPE_UINT8); + min_length = vals.min.num; + max_length = vals.max.num; + if(min_length == 0) { + min_length = 1; + } + + found_length = true; + } + + if(type->info.str.pat_count) { + //checkAL aici de fapt trebuie sa facem AND si NOT intre toate expresiile, in functie de modifier + // int modifier = type->info.str.patterns[i].expr[0]; + if(expression) { + free(expression); + expression = 0; + } + expression = strdup((char*)(type->info.str.patterns[0].expr + 1)); + } + + if(type->der) { + type = &type->der->type; + } + else { + break; + } + } while(1); + + if(expression) { + char *ret = rand_regex(expression); + if(ret == 0) { + log_error("rand_regex failed"); + free(expression); + return 0; + } + + while(strlen(ret) < min_length) { + char *add = rand_regex(expression); + if(add == 0) { + log_error("rand_regex failed"); + free(expression); + free(ret); + return 0; + } + + char *newret = 0; + asprintf(&newret, "%s%s", ret, add); + free(add); + free(ret); + ret = newret; + } + free(expression); + + if(ret == 0) { + log_error("rand_regex failed"); + return 0; + } + + if(max_length && (strlen(ret) > max_length)) { + ret[max_length] = 0; + } + + return ret; + } + else { + return rand_string(min_length, max_length); + } + } break; + + case LY_TYPE_INT8: + case LY_TYPE_UINT8: + case LY_TYPE_INT16: + case LY_TYPE_UINT16: + case LY_TYPE_INT32: + case LY_TYPE_UINT32: + case LY_TYPE_INT64: + case LY_TYPE_UINT64: { + const char *expr = 0; + + do { + if(type->info.num.range) { + expr = type->info.num.range->expr; + } + + if(type->der) { + type = &type->der->type; + } + else { + break; + } + } while(1); + + int64_t r = rand_range(expr, type->base).value.num; + if(type->base == LY_TYPE_UINT8) { + asprintf(&ret, "%"PRIu8, (uint8_t)r); + } + else if(type->base == LY_TYPE_UINT16) { + asprintf(&ret, "%"PRIu16, (uint16_t)r); + } + else if(type->base == LY_TYPE_UINT32) { + asprintf(&ret, "%"PRIu32, (uint32_t)r); + } + else if(type->base == LY_TYPE_UINT64) { + asprintf(&ret, "%"PRIu64, (uint64_t)r); + } + else if(type->base == LY_TYPE_INT8) { + asprintf(&ret, "%"PRId8, (int8_t)r); + } + else if(type->base == LY_TYPE_INT16) { + asprintf(&ret, "%"PRId16, (int16_t)r); + } + else if(type->base == LY_TYPE_INT32) { + asprintf(&ret, "%"PRId32, (int32_t)r); + } + else if(type->base == LY_TYPE_INT64) { + asprintf(&ret, "%"PRId64, (int64_t)r); + } + + return ret; + } break; + + case LY_TYPE_DEC64: { + const char *expr = 0; + int digits = -1; + char fmt[10]; + char *ret = 0; + + do { + if(type->info.dec64.range) { + expr = type->info.dec64.range->expr; + } + + if(digits == -1) { + digits = type->info.dec64.dig; + } + + if(type->der) { + type = &type->der->type; + } + else { + break; + } + } while(1); + + rand_range_t dr = rand_range(expr, LY_TYPE_DEC64); + sprintf(fmt, "%%.%df", digits); + + //19 digits total, including decimal part + int intdig = 19 - digits; + double max_val = 9.223372036854775807; + + while(fabs(dr.value.dec) > (pow(10, intdig - 1) * max_val)) { + dr.value.dec /= 10; + } + + asprintf(&ret, fmt, dr.value.dec); + return ret; + } break; + + case LY_TYPE_BITS: + ret = (char*)malloc(1); + if(ret == 0) { + log_error("malloc failed"); + return 0; + } + ret[0] = 0; + + for(int i = 0; i < type->info.bits.count; i++) { + if(rand_bool()) { + const char *val = type->info.bits.bit[i].name; + bool first = (ret == 0); + ret = (char*)realloc(ret, sizeof(char) * (strlen(ret) + 1 + strlen(val) + 1)); + if(ret == 0) { + log_error("malloc failed"); + return 0; + } + + if(!first) { + strcat(ret, " "); + } + strcat(ret, val); + } + } + return ret; + break; + + case LY_TYPE_BINARY: { + int length = 1; + char *ret = 0; + + do { + if(type->info.binary.length) { + rand_range_t vals = rand_range(type->info.binary.length->expr, LY_TYPE_UINT16); + length = vals.min.num; + if(length == 0) { + length = 1; + } + } + + if(type->der) { + type = &type->der->type; + } + else { + break; + } + } while(1); + + uint8_t *data = (uint8_t *)malloc(sizeof(uint8_t) * length); + if(!data) { + log_error("bad malloc"); + return 0; + } + + for(int i = 0; i < length; i++) { + data[i] = rand_uint8(); + } + + ret = b64_encode(data, length); + free(data); + return ret; + } break; + + case LY_TYPE_LEAFREF: + case LY_TYPE_UNION: + case LY_TYPE_INST: + asprintf(&ret, "{late_resolve_%s}", type->der->name); + log_error("needed: %s", ret); + assert(0); + return ret; + break; + + case LY_TYPE_UNKNOWN: + default: + asprintf(&ret, "{unimplemented_%s}", type->der->name); + log_error("can't generate random for: %s", type->der->name); + assert(0); + return ret; + break; + } +} + +uint8_t rand_uint8(void) { + return rand() % 256; +} + +int8_t rand_int8(void) { + return (int8_t)rand_uint8(); +} + +uint16_t rand_uint16(void) { + return rand() % 65536; +} + +int16_t rand_int16(void) { + return (int16_t)rand_uint16(); +} + +uint32_t rand_uint32(void) { + uint32_t x = rand_uint16(); + x <<= 16; + x += rand_uint16(); + return x; +} + +int32_t rand_int32(void) { + return (int32_t)rand_uint32(); +} + +uint64_t rand_uint64(void) { + uint64_t x = rand_uint32(); + x <<= 32; + x += rand_uint32(); + return x; +} + +int64_t rand_int64(void) { + return (int64_t)rand_uint64(); +} + +bool rand_bool(void) { + return ((rand() & 0x01) == 1); +} + +char *rand_regex(const char *regexp) { + assert(regexp); + + char buffer[8192]; + char *cmd = 0; + static int run_time = 0; + + if(framework_arguments.no_rand) { + run_time++; + asprintf(&cmd, "regxstring %d '%s'", run_time, regexp); + } + else { + asprintf(&cmd, "regxstring '%s'", regexp); + } + + FILE* pipe = popen(cmd, "r"); + free(cmd); + + if (!pipe) { + log_error("popen() failed"); + return 0; + } + + fgets(buffer, sizeof(buffer), pipe); + pclose(pipe); + + char *ret = strdup(buffer); + ret[strlen(ret) - 1] = 0; //remove trailing \n + + return ret; +} + +char *rand_mac_address(void) { + char *ret = 0; + + asprintf(&ret, "%02x:%02x:%02x:%02x:%02x:%02x", rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8(), rand_uint8()); + return ret; +} + +static char *rand_string(int min_length, int max_length) { + assert(min_length >= 0); + assert(min_length <= max_length); + + char charset[] = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + int length = 1; + if(min_length == max_length) { + length = min_length; + } + else { + if((framework_config.debug_max_string_size) && (framework_config.debug_max_string_size < max_length)) { + max_length = framework_config.debug_max_string_size; + } + + length = min_length + rand_uint16() % (max_length - min_length); + } + + char *ret = (char *)malloc(length + 1); + if(!ret) { + log_error("bad malloc"); + return 0; + } + + for(int i = 0; i < length; i++) { + ret[i] = charset[(rand_uint8() % (sizeof(charset) - 1))]; + } + ret[length] = 0; + return ret; +} + +static struct lys_ident *rand_identity(struct lys_ident *type) { + assert(type); + + struct lys_ident **found_identities; + int total = context_get_identity_leafs_of_type(type, &found_identities); + if(total == 0) { + return 0; + } + + int chosen = rand_uint16() % total; + struct lys_ident *ret = found_identities[chosen]; + free(found_identities); + + return ret; +} + + +static int64_t rand_range_type_int_min(LY_DATA_TYPE type) { + switch (type) { + case LY_TYPE_UINT8: + return 0; + break; + + case LY_TYPE_INT8: + return INT8_MIN; + break; + + case LY_TYPE_UINT16: + return 0; + break; + + case LY_TYPE_INT16: + return INT16_MIN; + break; + + case LY_TYPE_UINT32: + return 0; + break; + + case LY_TYPE_INT32: + return INT32_MIN; + break; + + case LY_TYPE_UINT64: + return 0; + break; + + case LY_TYPE_INT64: + return INT64_MIN; + break; + + default: + return 0; + assert(0); + break; + } +} + +static int64_t rand_range_type_int_max(LY_DATA_TYPE type) { + switch (type) { + case LY_TYPE_UINT8: + return UINT8_MAX; + break; + + case LY_TYPE_INT8: + return INT8_MAX; + break; + + case LY_TYPE_UINT16: + return UINT16_MAX; + break; + + case LY_TYPE_INT16: + return INT16_MAX; + break; + + case LY_TYPE_UINT32: + return UINT32_MAX; + break; + + case LY_TYPE_INT32: + return INT32_MAX; + break; + + case LY_TYPE_UINT64: + return INT64_MAX; //yes, intended + break; + + case LY_TYPE_INT64: + return INT64_MAX; + break; + + default: + return 0; + assert(0); + break; + } +} + +static rand_range_t rand_range(const char *range, const LY_DATA_TYPE type) { + char *working_range = 0; + rand_range_t ret; + ret.value.num = 0; + ret.min.num = 0; + ret.max.num = 0; + + if (range) { + //remove spaces + char *rrange = (char*)malloc(sizeof(char) * (strlen(range) + 1)); + if (!rrange) { + log_error("bad malloc"); + return ret; + } + + int i = 0; + int j = 0; + while (range[i]) { + if ((range[i] != ' ') && (range[i] != '\r') && (range[i] != '\n')) { + rrange[j] = range[i]; + j++; + } + i++; + } + rrange[j] = 0; + + //split the range into OR ranges + //first count how many different ranges exist + int chosen_range = 1; + char *search = strchr(rrange, '|'); + while (search) { + chosen_range++; + search = strchr(search + 1, '|'); + } + + //choose a random one + chosen_range = rand_uint16() % chosen_range; + int current_range = 0; + char *token; + token = strtok(rrange, "|"); + while (token) { + if (current_range == chosen_range) { + working_range = strdup(token); + } + current_range++; + token = strtok(0, "|"); + } + free(rrange); + } + + //now parse working_range according to type + if (type == LY_TYPE_DEC64) { + double min = -922337203685477580.8; + double max = 922337203685477580.7; + bool negative = false; + + if (working_range) { + min = 0; + max = 0; + + int i = 0; + if ((working_range[i] == 'm') || (working_range[i] == 'M')) { + min = -922337203685477580.8; + while (working_range[i] != '.') { + i++; + } + } + else { + if (working_range[i] == '-') { + negative = true; + i++; + } + + while ((working_range[i] >= '0') && (working_range[i] <= '9')) { + min *= 10; + min += working_range[i] - '0'; + i++; + } + } + + //working_range[i...] is either '.', ".." or \0 + if (working_range[i] == '.') { + if (working_range[i + 1] != '.') { + i++; + int power = 0; + while ((working_range[i] >= '0') && (working_range[i] <= '9')) { + power--; + min += (working_range[i] - '0') * pow(10, power); + i++; + } + } + else { + i += 2; //skip ".." + } + } + + if (negative) { + min *= -1; + negative = false; + } + + if (working_range[i] == 0) { + //single value + max = min; + } + else { + //there's also an upper value + if ((working_range[i] == 'm') || (working_range[i] == 'M')) { + max = 922337203685477580.7; + } + else { + if (working_range[i] == '-') { + negative = true; + i++; + } + + while ((working_range[i] >= '0') && (working_range[i] <= '9')) { + max *= 10; + max += working_range[i] - '0'; + i++; + } + } + + //working_range[i...] is either '.', or \0 + if (working_range[i] == '.') { + i++; + int power = 0; + while ((working_range[i] >= '0') && (working_range[i] <= '9')) { + power--; + max += (working_range[i] - '0') * pow(10, power); + i++; + } + } + + if (negative) { + max *= -1; + negative = false; + } + } + } + + ret.value.dec = rand() / 1.0 / RAND_MAX; + ret.value.dec = (max - min) * ret.value.dec + min; + ret.min.dec = min; + ret.max.dec = max; + } + else { + int64_t min = rand_range_type_int_min(type); + int64_t max = rand_range_type_int_max(type); + bool negative = false; + + if (working_range) { + min = 0; + max = 0; + + int i = 0; + if ((working_range[i] == 'm') || (working_range[i] == 'M')) { + min = rand_range_type_int_min(type); + while (working_range[i] != '.') { + i++; + } + } + else { + if (working_range[i] == '-') { + negative = true; + i++; + } + + while ((working_range[i] >= '0') && (working_range[i] <= '9')) { + min *= 10; + min += working_range[i] - '0'; + i++; + } + } + + //working_range[i...] is either ".." or \0 + if (working_range[i] == '.') { + i += 2; //skip ".." + } + + if (negative) { + min *= -1; + negative = false; + } + + if (working_range[i] == 0) { + //single value + max = min; + } + else { + //there's also an upper value + if ((working_range[i] == 'm') || (working_range[i] == 'M')) { + max = rand_range_type_int_max(type); + } + else { + if (working_range[i] == '-') { + negative = true; + i++; + } + + while ((working_range[i] >= '0') && (working_range[i] <= '9')) { + max *= 10; + max += working_range[i] - '0'; + i++; + } + } + + if (negative) { + max *= -1; + negative = false; + } + + } + } + + double ch = rand() / 1.0 / RAND_MAX; + ret.value.num = (max - min) * ch + min; + ret.min.num = min; + ret.max.num = max; + } + + free(working_range); + + return ret; +} + +static char *rand_date_and_time(void) { + time_t t = rand_uint32() / 2; + struct tm lt; + (void)localtime_r(&t, <); + + char *ret = (char *)malloc(21); + if(!ret) { + log_error("bad malloc"); + return 0; + } + strftime(ret, 21, "%Y-%m-%dT%H:%M:%SZ", <); + return ret; +} + +static char *rand_ipv4_address(void) { + char *ret = 0; + uint8_t ip1 = rand_uint8(); + uint8_t ip2 = rand_uint8(); + uint8_t ip3 = rand_uint8(); + uint8_t ip4 = rand_uint8(); + + asprintf(&ret, "%d.%d.%d.%d", ip1, ip2, ip3, ip4); + return ret; +} + +static char *rand_ipv6_address(void) { + char *ret = 0; + + uint16_t ip1 = rand_uint16(); + uint16_t ip2 = rand_uint16(); + uint16_t ip3 = rand_uint16(); + uint16_t ip4 = rand_uint16(); + uint16_t ip5 = rand_uint16(); + uint16_t ip6 = rand_uint16(); + uint16_t ip7 = rand_uint16(); + uint16_t ip8 = rand_uint16(); + + asprintf(&ret, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", ip1, ip2, ip3, ip4, ip5, ip6, ip7, ip8); + return ret; +} + +static char *rand_uuid(void) { + char *ret = 0; + + //8-4-4-4-12 + uint32_t v1 = rand_uint32(); + uint16_t v2 = rand_uint16(); + uint16_t v3 = rand_uint16(); + uint16_t v4 = rand_uint16(); + uint16_t v5 = rand_uint16(); + uint32_t v6 = rand_uint32(); + + asprintf(&ret, "%08x-%04x-%04x-%04x-%04x%08x", v1, v2, v3, v4, v5, v6); + + return ret; +}