From 52c2ec3202911faba9a0bb8ea75a06911d35a746 Mon Sep 17 00:00:00 2001 From: Miroslav Zagorac Date: Thu, 10 Mar 2022 00:03:24 +0100 Subject: [PATCH] MAJOR: opentracing: reenable usage of vars to transmit opentracing context Since commit 3a4bedccc ("MEDIUM: vars: replace the global name index with a hash") the names of HAProxy variables are no longer saved, ie their 64-bit hashes are saved instead. This is very convenient for the HAProxy itself, but for the OpenTracing module it is a problem because the names of the variables are important when transferring the OpenTracing context. Namely, this context consists of an unknown amount of data stored in a key-value format. The number of these data (and the name of the variable used for this purpose) is determined with the configuration of the OpenTracing filter, as well as with the tracer used. The two previous sentences seem to be in conflict, but that is only so at first glance. The function in the OpenTracing filter used to read the context does not really know this, neither their number nor its name. The only thing that function actually knows is the prefix of the variable names used for context transfer, and by that it could find all the necessary data. Of course, until the application of the above-mentioned commit. The problem is solved in a very simple way: in a common variable that the filter always knows its name, the names of all variables that are the product of the OpenTracing context are saved. The names of these context variables can only be added to that common variable. When that variable is no longer needed (when we no longer need context), it is deleted. The format for saving data to this common variable is as follows: +-----+---------------+-- .. --+-----+---------------+ | len | variable name | | len | variable name | +-----+---------------+-- .. --+-----+---------------+ The amount of memory space used to store the length of the name is 1 byte, with a sign (the minus sign is provided for inactive records, but this is not currently used). This means that the maximum length of the variable name to be saved is 127 characters, which is quite enough for use in the filter. The buffer size for such data storage is global.tune.bufsize. This patch must be backported in 2.5. --- addons/ot/include/debug.h | 1 + addons/ot/include/vars.h | 8 + addons/ot/src/vars.c | 526 +++++++++++++++++++++++++++++--------- 3 files changed, 418 insertions(+), 117 deletions(-) diff --git a/addons/ot/include/debug.h b/addons/ot/include/debug.h index 6311216a69..6274961014 100644 --- a/addons/ot/include/debug.h +++ b/addons/ot/include/debug.h @@ -44,6 +44,7 @@ # define FLT_OT_RETURN_PTR(a) FLT_OT_RETURN_EX((a), void *, "%p") # define FLT_OT_DBG_IFDEF(a,b) a # define FLT_OT_DBG_ARGS(a, ...) a, ##__VA_ARGS__ +# define FLT_OT_DBG_BUF(a,b) do { FLT_OT_DBG((a), "%p:{ %zu %p %zu %zu }", (b), (b)->size, (b)->area, (b)->data, (b)->head); } while (0) struct flt_ot_debug { #ifndef DEBUG_OT_SYSTIME diff --git a/addons/ot/include/vars.h b/addons/ot/include/vars.h index c683b6bc6f..550cc89171 100644 --- a/addons/ot/include/vars.h +++ b/addons/ot/include/vars.h @@ -21,9 +21,17 @@ #define _OPENTRACING_VARS_H_ #define FLT_OT_VARS_SCOPE "txn" +#define FLT_OT_VAR_CTX_SIZE int8_t #define FLT_OT_VAR_CHAR_DASH 'D' #define FLT_OT_VAR_CHAR_SPACE 'S' +struct flt_ot_ctx { + char value[BUFSIZ]; + int value_len; +}; + +typedef int (*flt_ot_ctx_loop_cb)(struct sample *, size_t, const char *, const char *, const char *, FLT_OT_VAR_CTX_SIZE, char **, void *); + #ifndef DEBUG_OT # define flt_ot_vars_dump(...) while (0) diff --git a/addons/ot/src/vars.c b/addons/ot/src/vars.c index f2e1050a48..e99bab16c7 100644 --- a/addons/ot/src/vars.c +++ b/addons/ot/src/vars.c @@ -46,7 +46,7 @@ static void flt_ot_vars_scope_dump(struct vars *vars, const char *scope) vars_rdlock(vars); list_for_each_entry(var, &(vars->head), l) - FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area); + FLT_OT_DBG(2, "'%s.%016" PRIx64 "' -> '%.*s'", scope, var->name_hash, (int)b_data(&(var->data.u.str)), b_orig(&(var->data.u.str))); vars_rdunlock(vars); } @@ -119,33 +119,58 @@ static inline void flt_ot_smp_init(struct stream *s, struct sample *smp, uint op /*** * NAME - * flt_ot_get_vars - + * flt_ot_smp_add - * * ARGUMENTS - * s - - * scope - + * data - + * blk - + * len - + * err - * * DESCRIPTION * - * * RETURN VALUE - * Returns the struct vars pointer for a stream and scope, or NULL if it does - * not exist. + * - */ -static inline struct vars *flt_ot_get_vars(struct stream *s, const char *scope) +static int flt_ot_smp_add(struct sample_data *data, const char *name, size_t len, char **err) { - struct vars *retptr = NULL; + bool flag_alloc = 0; + int retval = FLT_OT_RET_ERROR; - if (strcasecmp(scope, "proc") == 0) - retptr = &(proc_vars); - else if (strcasecmp(scope, "sess") == 0) - retptr = (&(s->sess->vars)); - else if (strcasecmp(scope, "txn") == 0) - retptr = (&(s->vars_txn)); - else if ((strcasecmp(scope, "req") == 0) || (strcasecmp(scope, "res") == 0)) - retptr = (&(s->vars_reqres)); + FLT_OT_FUNC("%p, \"%.*s\", %zu, %p:%p", data, (int)len, name, len, FLT_OT_DPTR_ARGS(err)); - return retptr; + FLT_OT_DBG_BUF(2, &(data->u.str)); + + if (b_orig(&(data->u.str)) == NULL) { + data->type = SMP_T_BIN; + chunk_init(&(data->u.str), FLT_OT_MALLOC(global.tune.bufsize), global.tune.bufsize); + + flag_alloc = (b_orig(&(data->u.str)) != NULL); + } + + if (b_orig(&(data->u.str)) == NULL) { + FLT_OT_ERR("failed to add ctx '%.*s', not enough memory", (int)len, name); + } + else if (len > ((UINT64_C(1) << ((sizeof(FLT_OT_VAR_CTX_SIZE) << 3) - 1)) - 1)) { + FLT_OT_ERR("failed to add ctx '%.*s', too long name", (int)len, name); + } + else if ((len + sizeof(FLT_OT_VAR_CTX_SIZE)) > b_room(&(data->u.str))) { + FLT_OT_ERR("failed to add ctx '%.*s', too many names", (int)len, name); + } + else { + retval = b_data(&(data->u.str)); + + b_putchr(&(data->u.str), len); + (void)__b_putblk(&(data->u.str), name, len); + + FLT_OT_DBG_BUF(2, &(data->u.str)); + } + + if ((retval == FLT_OT_RET_ERROR) && flag_alloc) + FLT_OT_FREE(b_orig(&(data->u.str))); + + FLT_OT_RETURN_INT(retval); } @@ -184,10 +209,14 @@ static int flt_ot_normalize_name(char *var_name, size_t size, int *len, const ch /* Do nothing. */; else if (*len < (size - 1)) var_name[(*len)++] = '.'; - else + else { + FLT_OT_ERR("failed to normalize variable name, buffer too small"); + retval = -1; + } if (flag_cpy) { + /* Copy variable name without modification. */ retval = strlen(name); if ((*len + retval + 1) > size) { FLT_OT_ERR("failed to normalize variable name, buffer too small"); @@ -195,6 +224,7 @@ static int flt_ot_normalize_name(char *var_name, size_t size, int *len, const ch retval = -1; } else { (void)memcpy(var_name + *len, name, retval + 1); + *len += retval; } } else { @@ -274,6 +304,204 @@ static int flt_ot_var_name(const char *scope, const char *prefix, const char *na } +/*** + * NAME + * flt_ot_ctx_loop - + * + * ARGUMENTS + * smp - + * scope - + * prefix - + * err - + * func - + * ptr - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static int flt_ot_ctx_loop(struct sample *smp, const char *scope, const char *prefix, char **err, flt_ot_ctx_loop_cb func, void *ptr) +{ + FLT_OT_VAR_CTX_SIZE var_ctx_size; + char var_name[BUFSIZ], var_ctx[BUFSIZ]; + int i, var_name_len, var_ctx_len, rc, n = 1, retval = 0; + + FLT_OT_FUNC("%p, \"%s\", \"%s\", %p:%p, %p, %p", smp, scope, prefix, FLT_OT_DPTR_ARGS(err), func, ptr); + + /* + * The variable in which we will save the name of the OpenTracing + * context variable. + */ + var_name_len = flt_ot_var_name(scope, prefix, NULL, 0, var_name, sizeof(var_name), err); + if (var_name_len == -1) + FLT_OT_RETURN_INT(FLT_OT_RET_ERROR); + + /* + * Here we will try to find all the previously recorded variables from + * the currently set OpenTracing context. If we find the required + * variable and it is marked as deleted, we will mark it as active. + * If we do not find it, then it is added to the end of the previously + * saved names. + */ + if (vars_get_by_name(var_name, var_name_len, smp, NULL) == 0) { + FLT_OT_DBG(2, "ctx '%s' no variable found", var_name); + } + else if (smp->data.type != SMP_T_BIN) { + FLT_OT_ERR("ctx '%s' invalid data type %d", var_name, smp->data.type); + + retval = FLT_OT_RET_ERROR; + } + else { + FLT_OT_DBG_BUF(2, &(smp->data.u.str)); + + for (i = 0; i < b_data(&(smp->data.u.str)); i += sizeof(var_ctx_size) + var_ctx_len, n++) { + var_ctx_size = *((typeof(var_ctx_size) *)(b_orig(&(smp->data.u.str)) + i)); + var_ctx_len = abs(var_ctx_size); + + if ((i + sizeof(var_ctx_size) + var_ctx_len) > b_data(&(smp->data.u.str))) { + FLT_OT_ERR("ctx '%s' invalid data size", var_name); + + retval = FLT_OT_RET_ERROR; + + break; + } + + (void)memcpy(var_ctx, b_orig(&(smp->data.u.str)) + i + sizeof(var_ctx_size), var_ctx_len); + var_ctx[var_ctx_len] = '\0'; + + rc = func(smp, i, scope, prefix, var_ctx, var_ctx_size, err, ptr); + if (rc == FLT_OT_RET_ERROR) { + retval = FLT_OT_RET_ERROR; + + break; + } + else if (rc > 0) { + retval = n; + + break; + } + } + } + + FLT_OT_RETURN_INT(retval); +} + + +/*** + * NAME + * flt_ot_ctx_set_cb - + * + * ARGUMENTS + * smp - + * idx - + * scope - + * prefix - + * name - + * name_len - + * err - + * ptr - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static int flt_ot_ctx_set_cb(struct sample *smp, size_t idx, const char *scope, const char *prefix, const char *name, FLT_OT_VAR_CTX_SIZE name_len, char **err, void *ptr) +{ + struct flt_ot_ctx *ctx = ptr; + int retval = 0; + + FLT_OT_FUNC("%p, %zu, \"%s\", \"%s\", \"%s\", %hhd, %p:%p, %p", smp, idx, scope, prefix, name, name_len, FLT_OT_DPTR_ARGS(err), ptr); + + if ((name_len == ctx->value_len) && (strncmp(name, ctx->value, name_len) == 0)) { + FLT_OT_DBG(2, "ctx '%s' found\n", name); + + retval = 1; + } + + FLT_OT_RETURN_INT(retval); +} + + +/*** + * NAME + * flt_ot_ctx_set - + * + * ARGUMENTS + * s - + * scope - + * prefix - + * name - + * opt - + * err - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static int flt_ot_ctx_set(struct stream *s, const char *scope, const char *prefix, const char *name, uint opt, char **err) +{ + struct flt_ot_ctx ctx; + struct sample smp_ctx; + char var_name[BUFSIZ]; + bool flag_alloc = 0; + int rc, var_name_len, retval = FLT_OT_RET_ERROR; + + FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, opt, FLT_OT_DPTR_ARGS(err)); + + /* + * The variable in which we will save the name of the OpenTracing + * context variable. + */ + var_name_len = flt_ot_var_name(scope, prefix, NULL, 0, var_name, sizeof(var_name), err); + if (var_name_len == -1) + FLT_OT_RETURN_INT(retval); + + /* Normalized name of the OpenTracing context variable. */ + ctx.value_len = flt_ot_var_name(name, NULL, NULL, 0, ctx.value, sizeof(ctx.value), err); + if (ctx.value_len == -1) + FLT_OT_RETURN_INT(retval); + + flt_ot_smp_init(s, &smp_ctx, opt, 0, NULL); + + retval = flt_ot_ctx_loop(&smp_ctx, scope, prefix, err, flt_ot_ctx_set_cb, &ctx); + if (retval == 0) { + rc = flt_ot_smp_add(&(smp_ctx.data), ctx.value, ctx.value_len, err); + if (rc == FLT_OT_RET_ERROR) + retval = FLT_OT_RET_ERROR; + + flag_alloc = (rc == 0); + } + + if (retval == FLT_OT_RET_ERROR) { + /* Do nothing. */ + } + else if (retval > 0) { + FLT_OT_DBG(2, "ctx '%s' data found", ctx.value); + } + else if (vars_set_by_name_ifexist(var_name, var_name_len, &smp_ctx) == 0) { + FLT_OT_ERR("failed to set ctx '%s'", var_name); + + retval = FLT_OT_RET_ERROR; + } + else { + FLT_OT_DBG(2, "ctx '%s' -> '%.*s' set", var_name, (int)b_data(&(smp_ctx.data.u.str)), b_orig(&(smp_ctx.data.u.str))); + + retval = b_data(&(smp_ctx.data.u.str)); + } + + if (flag_alloc) + FLT_OT_FREE(b_orig(&(smp_ctx.data.u.str))); + + FLT_OT_RETURN_INT(retval); +} + + /*** * NAME * flt_ot_var_register - @@ -311,7 +539,7 @@ int flt_ot_var_register(const char *scope, const char *prefix, const char *name, if (vars_check_arg(&arg, err) == 0) { FLT_OT_ERR_APPEND("failed to register variable '%s': %s", var_name, *err); } else { - FLT_OT_DBG(2, "variable '%s' registered", arg.data.var.name); + FLT_OT_DBG(2, "variable '%s' registered", var_name); retval = var_name_len; } @@ -359,6 +587,58 @@ int flt_ot_var_set(struct stream *s, const char *scope, const char *prefix, cons FLT_OT_DBG(2, "variable '%s' set", var_name); retval = var_name_len; + + if (strcmp(scope, FLT_OT_VARS_SCOPE) == 0) + retval = flt_ot_ctx_set(s, scope, prefix, name, opt, err); + } + + FLT_OT_RETURN_INT(retval); +} + + +/*** + * NAME + * flt_ot_vars_unset_cb - + * + * ARGUMENTS + * smp - + * idx - + * scope - + * prefix - + * name - + * name_len - + * err - + * ptr - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static int flt_ot_vars_unset_cb(struct sample *smp, size_t idx, const char *scope, const char *prefix, const char *name, FLT_OT_VAR_CTX_SIZE name_len, char **err, void *ptr) +{ + struct sample smp_ctx; + char var_ctx[BUFSIZ]; + int var_ctx_len, retval = FLT_OT_RET_ERROR; + + FLT_OT_FUNC("%p, %zu, \"%s\", \"%s\", \"%s\", %hhd, %p:%p, %p", smp, idx, scope, prefix, name, name_len, FLT_OT_DPTR_ARGS(err), ptr); + + var_ctx_len = flt_ot_var_name(scope, prefix, name, 1, var_ctx, sizeof(var_ctx), err); + if (var_ctx_len == -1) { + FLT_OT_ERR("ctx '%s' invalid", name); + + FLT_OT_RETURN_INT(retval); + } + + flt_ot_smp_init(smp->strm, &smp_ctx, smp->opt, 0, NULL); + + if (vars_unset_by_name_ifexist(var_ctx, var_ctx_len, &smp_ctx) == 0) { + FLT_OT_ERR("ctx '%s' no variable found", var_ctx); + } else { + FLT_OT_DBG(2, "ctx '%s' unset", var_ctx); + + retval = 0; } FLT_OT_RETURN_INT(retval); @@ -384,47 +664,122 @@ int flt_ot_var_set(struct stream *s, const char *scope, const char *prefix, cons */ int flt_ot_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err) { - struct sample smp; - struct vars *vars; - struct var *var, *var_back; - char var_prefix[BUFSIZ], var_name[BUFSIZ]; - uint size; - int var_prefix_len, var_name_len, retval = -1; + struct sample smp_ctx; + char var_name[BUFSIZ]; + int var_name_len, retval; FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err)); - vars = flt_ot_get_vars(s, scope); - if (vars == NULL) - FLT_OT_RETURN_INT(retval); + flt_ot_smp_init(s, &smp_ctx, opt, 0, NULL); - var_prefix_len = flt_ot_var_name(NULL, prefix, NULL, 0, var_prefix, sizeof(var_prefix), err); - if (var_prefix_len == -1) - FLT_OT_RETURN_INT(retval); + retval = flt_ot_ctx_loop(&smp_ctx, scope, prefix, err, flt_ot_vars_unset_cb, NULL); + if (retval != FLT_OT_RET_ERROR) { + /* + * After all ctx variables have been unset, the variable used + * to store their names should also be unset. + */ + var_name_len = flt_ot_var_name(scope, prefix, NULL, 0, var_name, sizeof(var_name), err); + if (var_name_len == -1) + FLT_OT_RETURN_INT(FLT_OT_RET_ERROR); - retval = 0; + flt_ot_smp_init(s, &smp_ctx, opt, 0, NULL); - vars_wrlock(vars); - list_for_each_entry_safe(var, var_back, &(vars->head), l) { - FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_prefix, var->name, var_prefix_len); + if (vars_unset_by_name_ifexist(var_name, var_name_len, &smp_ctx) == 0) { + FLT_OT_DBG(2, "variable '%s' not found", var_name); + } else { + FLT_OT_DBG(2, "variable '%s' unset", var_name); - if (strncmp(var_prefix, var->name, var_prefix_len) == 0) { - var_name_len = snprintf(var_name, sizeof(var_name), "%s.%s", scope, var->name); - if ((var_name_len == -1) || (var_name_len >= sizeof(var_name))) { - FLT_OT_DBG(2, "'%s.%s' variable name too long", scope, var->name); - - break; - } - - FLT_OT_DBG(2, "- '%s' -> '%.*s'", var_name, (int)var->data.u.str.data, var->data.u.str.area); - - size = var_clear(var, 1); - flt_ot_smp_init(s, &smp, opt, 0, NULL); - var_accounting_diff(vars, smp.sess, smp.strm, -size); - - retval++; + retval = 1; } } - vars_wrunlock(vars); + + FLT_OT_RETURN_INT(retval); +} + + +/*** + * NAME + * flt_ot_vars_get_cb - + * + * ARGUMENTS + * smp - + * idx - + * scope - + * prefix - + * name - + * name_len - + * err - + * ptr - + * + * DESCRIPTION + * - + * + * RETURN VALUE + * - + */ +static int flt_ot_vars_get_cb(struct sample *smp, size_t idx, const char *scope, const char *prefix, const char *name, FLT_OT_VAR_CTX_SIZE name_len, char **err, void *ptr) +{ + struct otc_text_map **map = ptr; + struct sample smp_ctx; + char var_ctx[BUFSIZ], ot_var_name[BUFSIZ], ch; + int var_ctx_len, ot_var_name_len, retval = FLT_OT_RET_ERROR; + + FLT_OT_FUNC("%p, %zu, \"%s\", \"%s\", \"%s\", %hhd, %p:%p, %p", smp, idx, scope, prefix, name, name_len, FLT_OT_DPTR_ARGS(err), ptr); + + var_ctx_len = flt_ot_var_name(scope, prefix, name, 1, var_ctx, sizeof(var_ctx), err); + if (var_ctx_len == -1) { + FLT_OT_ERR("ctx '%s' invalid", name); + + FLT_OT_RETURN_INT(retval); + } + + flt_ot_smp_init(smp->strm, &smp_ctx, smp->opt, 0, NULL); + + if (vars_get_by_name(var_ctx, var_ctx_len, &smp_ctx, NULL) != 0) { + FLT_OT_DBG(2, "'%s' -> '%.*s'", var_ctx, (int)b_data(&(smp_ctx.data.u.str)), b_orig(&(smp_ctx.data.u.str))); + + if (*map == NULL) { + *map = otc_text_map_new(NULL, 8); + if (*map == NULL) { + FLT_OT_ERR("failed to create map data"); + + FLT_OT_RETURN_INT(FLT_OT_RET_ERROR); + } + } + + /* + * Eh, because the use of some characters is not allowed + * in the variable name, the conversion of the replaced + * characters to the original is performed here. + */ + for (ot_var_name_len = 0; (ch = name[ot_var_name_len]) != '\0'; ot_var_name_len++) + if (ot_var_name_len >= (FLT_OT_TABLESIZE(ot_var_name) - 1)) { + FLT_OT_ERR("failed to reverse variable name, buffer too small"); + + otc_text_map_destroy(map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE); + + break; + } else { + ot_var_name[ot_var_name_len] = (ch == FLT_OT_VAR_CHAR_DASH) ? '-' : ((ch == FLT_OT_VAR_CHAR_SPACE) ? ' ' : ch); + } + ot_var_name[ot_var_name_len] = '\0'; + + if (*map == NULL) { + retval = FLT_OT_RET_ERROR; + } + else if (otc_text_map_add(*map, ot_var_name, ot_var_name_len, b_orig(&(smp_ctx.data.u.str)), b_data(&(smp_ctx.data.u.str)), OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1) { + FLT_OT_ERR("failed to add map data"); + + otc_text_map_destroy(map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE); + + retval = FLT_OT_RET_ERROR; + } + else { + retval = 0; + } + } else { + FLT_OT_DBG(2, "ctx '%s' no variable found", var_ctx); + } FLT_OT_RETURN_INT(retval); } @@ -449,77 +804,14 @@ int flt_ot_vars_unset(struct stream *s, const char *scope, const char *prefix, u */ struct otc_text_map *flt_ot_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err) { - struct vars *vars; - const struct var *var; - char var_name[BUFSIZ], ot_var_name[BUFSIZ]; - int rc, i; + struct sample smp_ctx; struct otc_text_map *retptr = NULL; FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err)); - vars = flt_ot_get_vars(s, scope); - if (vars == NULL) - FLT_OT_RETURN_PTR(retptr); + flt_ot_smp_init(s, &smp_ctx, opt, 0, NULL); - rc = flt_ot_var_name(NULL, prefix, NULL, 0, var_name, sizeof(var_name), err); - if (rc == -1) - FLT_OT_RETURN_PTR(retptr); - - vars_rdlock(vars); - list_for_each_entry(var, &(vars->head), l) { - FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_name, var->name, rc); - - if (strncmp(var_name, var->name, rc) == 0) { - FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area); - - if (retptr == NULL) { - retptr = otc_text_map_new(NULL, 8); - if (retptr == NULL) { - FLT_OT_ERR("failed to create data"); - - break; - } - } - - /* - * Eh, because the use of some characters is not allowed - * in the variable name, the conversion of the replaced - * characters to the original is performed here. - */ - for (i = 0; ; ) - if (i >= (FLT_OT_TABLESIZE(ot_var_name) - 1)) { - FLT_OT_ERR("failed to reverse variable name, buffer too small"); - - otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE); - - break; - } else { - char ch = var->name[rc + i + 1]; - - if (ch == '\0') - break; - else if (ch == FLT_OT_VAR_CHAR_DASH) - ch = '-'; - else if (ch == FLT_OT_VAR_CHAR_SPACE) - ch = ' '; - - ot_var_name[i++] = ch; - } - ot_var_name[i] = '\0'; - - if (retptr == NULL) { - break; - } - else if (otc_text_map_add(retptr, ot_var_name, i, var->data.u.str.area, var->data.u.str.data, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1) { - FLT_OT_ERR("failed to add map data"); - - otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE); - - break; - } - } - } - vars_rdunlock(vars); + (void)flt_ot_ctx_loop(&smp_ctx, scope, prefix, err, flt_ot_vars_get_cb, &retptr); ot_text_map_show(retptr);