summaryrefslogtreecommitdiffstats
path: root/addons/ot/src
diff options
context:
space:
mode:
Diffstat (limited to 'addons/ot/src')
-rw-r--r--addons/ot/src/cli.c397
-rw-r--r--addons/ot/src/conf.c764
-rw-r--r--addons/ot/src/event.c338
-rw-r--r--addons/ot/src/filter.c1176
-rw-r--r--addons/ot/src/group.c354
-rw-r--r--addons/ot/src/http.c312
-rw-r--r--addons/ot/src/opentracing.c1067
-rw-r--r--addons/ot/src/parser.c1225
-rw-r--r--addons/ot/src/pool.c223
-rw-r--r--addons/ot/src/scope.c634
-rw-r--r--addons/ot/src/util.c815
-rw-r--r--addons/ot/src/vars.c834
12 files changed, 8139 insertions, 0 deletions
diff --git a/addons/ot/src/cli.c b/addons/ot/src/cli.c
new file mode 100644
index 0000000..0080dbd
--- /dev/null
+++ b/addons/ot/src/cli.c
@@ -0,0 +1,397 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+/***
+ * NAME
+ * flt_ot_cli_set_msg -
+ *
+ * ARGUMENTS
+ * appctx -
+ * err -
+ * msg -
+ * cli_state -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void cmn_cli_set_msg(struct appctx *appctx, char *err, char *msg, int cli_state)
+{
+ struct cli_print_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
+ FLT_OT_FUNC("%p, %p, %p, %d", appctx, err, msg, cli_state);
+
+ if ((appctx == NULL) || ((err == NULL) && (msg == NULL)))
+ FLT_OT_RETURN();
+
+ ctx->err = (err == NULL) ? msg : err;
+ appctx->st0 = (ctx->err == NULL) ? CLI_ST_PROMPT : cli_state;
+
+ FLT_OT_DBG(1, "err(%d): \"%s\"", appctx->st0, ctx->err);
+
+ FLT_OT_RETURN();
+}
+
+
+#ifdef DEBUG_OT
+
+/***
+ * NAME
+ * flt_ot_cli_parse_debug -
+ *
+ * ARGUMENTS
+ * args -
+ * payload -
+ * appctx -
+ * private -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_cli_parse_debug(char **args, char *payload, struct appctx *appctx, void *private)
+{
+ char *err = NULL, *msg = NULL;
+ uint8_t value;
+ int retval = 0;
+
+ FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
+
+ FLT_OT_ARGS_DUMP();
+
+ if (FLT_OT_ARG_ISVALID(2)) {
+ value = flt_ot_strtoll(args[2], 0, 255, &err);
+ if (err == NULL) {
+ _HA_ATOMIC_STORE(&(flt_ot_debug.level), value);
+
+ (void)memprintf(&msg, FLT_OT_CLI_CMD " : debug level set to %hhu", value);
+ } else {
+ retval = 1;
+ }
+ } else {
+ value = _HA_ATOMIC_LOAD(&(flt_ot_debug.level));
+
+ (void)memprintf(&msg, FLT_OT_CLI_CMD " : current debug level is %hhu", value);
+ }
+
+ cmn_cli_set_msg(appctx, err, msg, CLI_ST_PRINT_DYNERR);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+#endif /* DEBUG_OT */
+
+
+/***
+ * NAME
+ * flt_ot_cli_parse_disabled -
+ *
+ * ARGUMENTS
+ * args -
+ * payload -
+ * appctx -
+ * private -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_cli_parse_disabled(char **args, char *payload, struct appctx *appctx, void *private)
+{
+ char *msg = NULL;
+ bool value = (uintptr_t)private;
+ int retval = 0;
+
+ FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
+
+ FLT_OT_ARGS_DUMP();
+
+ FLT_OT_PROXIES_LIST_START() {
+ _HA_ATOMIC_STORE(&(conf->tracer->flag_disabled), value);
+
+ (void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : filter %sabled", FLT_OT_CLI_MSG_CAT(msg), value ? "dis" : "en");
+ } FLT_OT_PROXIES_LIST_END();
+
+ cmn_cli_set_msg(appctx, NULL, msg, CLI_ST_PRINT_DYNERR);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_cli_parse_option -
+ *
+ * ARGUMENTS
+ * args -
+ * payload -
+ * appctx -
+ * private -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_cli_parse_option(char **args, char *payload, struct appctx *appctx, void *private)
+{
+ char *msg = NULL;
+ bool value = (uintptr_t)private;
+ int retval = 0;
+
+ FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
+
+ FLT_OT_ARGS_DUMP();
+
+ FLT_OT_PROXIES_LIST_START() {
+ _HA_ATOMIC_STORE(&(conf->tracer->flag_harderr), value);
+
+ (void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : filter set %s-errors", FLT_OT_CLI_MSG_CAT(msg), value ? "hard" : "soft");
+ } FLT_OT_PROXIES_LIST_END();
+
+ cmn_cli_set_msg(appctx, NULL, msg, CLI_ST_PRINT_DYNERR);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_cli_parse_logging -
+ *
+ * ARGUMENTS
+ * args -
+ * payload -
+ * appctx -
+ * private -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_cli_parse_logging(char **args, char *payload, struct appctx *appctx, void *private)
+{
+ char *err = NULL, *msg = NULL;
+ uint8_t value;
+ int retval = 0;
+
+ FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
+
+ FLT_OT_ARGS_DUMP();
+
+ if (FLT_OT_ARG_ISVALID(2)) {
+ if (strcasecmp(args[2], FLT_OT_CLI_LOGGING_OFF) == 0) {
+ value = FLT_OT_LOGGING_OFF;
+ }
+ else if (strcasecmp(args[2], FLT_OT_CLI_LOGGING_ON) == 0) {
+ value = FLT_OT_LOGGING_ON;
+ }
+ else if (strcasecmp(args[2], FLT_OT_CLI_LOGGING_NOLOGNORM) == 0) {
+ value = FLT_OT_LOGGING_ON | FLT_OT_LOGGING_NOLOGNORM;
+ }
+ else {
+ (void)memprintf(&err, "'%s' : invalid value, use <" FLT_OT_CLI_LOGGING_OFF " | " FLT_OT_CLI_LOGGING_ON " | " FLT_OT_CLI_LOGGING_NOLOGNORM ">", args[2]);
+
+ retval = 1;
+ }
+
+ if (retval == 0) {
+ FLT_OT_PROXIES_LIST_START() {
+ _HA_ATOMIC_STORE(&(conf->tracer->logging), value);
+
+ (void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : logging is %s", FLT_OT_CLI_MSG_CAT(msg), FLT_OT_CLI_LOGGING_STATE(value));
+ } FLT_OT_PROXIES_LIST_END();
+ }
+ } else {
+ FLT_OT_PROXIES_LIST_START() {
+ value = _HA_ATOMIC_LOAD(&(conf->tracer->logging));
+
+ (void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : logging is currently %s", FLT_OT_CLI_MSG_CAT(msg), FLT_OT_CLI_LOGGING_STATE(value));
+ } FLT_OT_PROXIES_LIST_END();
+ }
+
+ cmn_cli_set_msg(appctx, err, msg, CLI_ST_PRINT_DYNERR);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_cli_parse_rate -
+ *
+ * ARGUMENTS
+ * args -
+ * payload -
+ * appctx -
+ * private -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_cli_parse_rate(char **args, char *payload, struct appctx *appctx, void *private)
+{
+ char *err = NULL, *msg = NULL;
+ uint32_t value;
+ int retval = 0;
+
+ FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
+
+ FLT_OT_ARGS_DUMP();
+
+ if (FLT_OT_ARG_ISVALID(2)) {
+ value = FLT_OT_FLOAT_U32(flt_ot_strtod(args[2], 0.0, FLT_OT_RATE_LIMIT_MAX, &err), FLT_OT_RATE_LIMIT_MAX);
+ if (err == NULL) {
+ FLT_OT_PROXIES_LIST_START() {
+ _HA_ATOMIC_STORE(&(conf->tracer->rate_limit), value);
+
+ (void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : rate limit set to %.2f", FLT_OT_CLI_MSG_CAT(msg), FLT_OT_U32_FLOAT(value, FLT_OT_RATE_LIMIT_MAX));
+ } FLT_OT_PROXIES_LIST_END();
+ } else {
+ retval = 1;
+ }
+ } else {
+ FLT_OT_PROXIES_LIST_START() {
+ value = _HA_ATOMIC_LOAD(&(conf->tracer->rate_limit));
+
+ (void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : current rate limit is %.2f", FLT_OT_CLI_MSG_CAT(msg), FLT_OT_U32_FLOAT(value, FLT_OT_RATE_LIMIT_MAX));
+ } FLT_OT_PROXIES_LIST_END();
+ }
+
+ cmn_cli_set_msg(appctx, err, msg, CLI_ST_PRINT_DYNERR);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_cli_parse_status -
+ *
+ * ARGUMENTS
+ * args -
+ * payload -
+ * appctx -
+ * private -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_cli_parse_status(char **args, char *payload, struct appctx *appctx, void *private)
+{
+ const char *nl = "";
+ char *msg = NULL;
+ int retval = 0;
+
+ FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
+
+ FLT_OT_ARGS_DUMP();
+ flt_ot_filters_dump();
+
+ (void)memprintf(&msg, " " FLT_OT_OPT_NAME " filter status\n" FLT_OT_STR_DASH_78);
+#ifdef DEBUG_OT
+ (void)memprintf(&msg, "%s\n debug level: 0x%02hhx\n", msg, flt_ot_debug.level);
+#endif
+
+ FLT_OT_PROXIES_LIST_START() {
+ (void)memprintf(&msg, "%s\n%s filter %s\n", msg, nl, conf->id);
+ (void)memprintf(&msg, "%s configuration: %s\n", msg, conf->cfg_file);
+ (void)memprintf(&msg, "%s disable count: %" PRIu64 " %" PRIu64 "\n\n", msg, conf->cnt.disabled[0], conf->cnt.disabled[1]);
+ (void)memprintf(&msg, "%s tracer %s\n", msg, conf->tracer->id);
+ (void)memprintf(&msg, "%s configuration: %s\n", msg, conf->tracer->config);
+ (void)memprintf(&msg, "%s plugin: %s\n", msg, conf->tracer->plugin);
+ (void)memprintf(&msg, "%s rate limit: %.2f %%\n", msg, FLT_OT_U32_FLOAT(conf->tracer->rate_limit, FLT_OT_RATE_LIMIT_MAX));
+ (void)memprintf(&msg, "%s hard errors: %s\n", msg, FLT_OT_STR_FLAG_YN(conf->tracer->flag_harderr));
+ (void)memprintf(&msg, "%s disabled: %s\n", msg, FLT_OT_STR_FLAG_YN(conf->tracer->flag_disabled));
+ (void)memprintf(&msg, "%s logging: %s\n", msg, FLT_OT_CLI_LOGGING_STATE(conf->tracer->logging));
+ (void)memprintf(&msg, "%s analyzers: %08x", msg, conf->tracer->analyzers);
+
+ nl = "\n";
+ } FLT_OT_PROXIES_LIST_END();
+
+ cmn_cli_set_msg(appctx, NULL, msg, CLI_ST_PRINT_DYNERR);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+static struct cli_kw_list cli_kws = { { }, {
+#ifdef DEBUG_OT
+ { { FLT_OT_CLI_CMD, "debug", NULL }, FLT_OT_CLI_CMD " debug [level] : set the OT filter debug level (default: get current debug level)", flt_ot_cli_parse_debug, NULL, NULL, NULL, 0 },
+#endif
+ { { FLT_OT_CLI_CMD, "disable", NULL }, FLT_OT_CLI_CMD " disable : disable the OT filter", flt_ot_cli_parse_disabled, NULL, NULL, (void *)1, 0 },
+ { { FLT_OT_CLI_CMD, "enable", NULL }, FLT_OT_CLI_CMD " enable : enable the OT filter", flt_ot_cli_parse_disabled, NULL, NULL, (void *)0, 0 },
+ { { FLT_OT_CLI_CMD, "soft-errors", NULL }, FLT_OT_CLI_CMD " soft-errors : turning off hard-errors mode", flt_ot_cli_parse_option, NULL, NULL, (void *)0, 0 },
+ { { FLT_OT_CLI_CMD, "hard-errors", NULL }, FLT_OT_CLI_CMD " hard-errors : enabling hard-errors mode", flt_ot_cli_parse_option, NULL, NULL, (void *)1, 0 },
+ { { FLT_OT_CLI_CMD, "logging", NULL }, FLT_OT_CLI_CMD " logging [state] : set logging state (default: get current logging state)", flt_ot_cli_parse_logging, NULL, NULL, NULL, 0 },
+ { { FLT_OT_CLI_CMD, "rate", NULL }, FLT_OT_CLI_CMD " rate [value] : set the rate limit (default: get current rate value)", flt_ot_cli_parse_rate, NULL, NULL, NULL, 0 },
+ { { FLT_OT_CLI_CMD, "status", NULL }, FLT_OT_CLI_CMD " status : show the OT filter status", flt_ot_cli_parse_status, NULL, NULL, NULL, 0 },
+ { /* END */ }
+}};
+
+
+/***
+ * NAME
+ * flt_ot_cli_init -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_cli_init(void)
+{
+ FLT_OT_FUNC("");
+
+ /* Register CLI keywords. */
+ cli_register_kw(&cli_kws);
+
+ FLT_OT_RETURN();
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/conf.c b/addons/ot/src/conf.c
new file mode 100644
index 0000000..c6375a6
--- /dev/null
+++ b/addons/ot/src/conf.c
@@ -0,0 +1,764 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+/***
+ * NAME
+ * flt_ot_conf_hdr_init -
+ *
+ * ARGUMENTS
+ * size -
+ * id -
+ * linenum -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static void *flt_ot_conf_hdr_init(size_t size, const char *id, int linenum, struct list *head, char **err)
+{
+ struct flt_ot_conf_hdr *retptr = NULL, *ptr;
+
+ FLT_OT_FUNC("%zu, \"%s\", %d, %p, %p:%p", size, id, linenum, head, FLT_OT_DPTR_ARGS(err));
+
+ if (head != NULL)
+ list_for_each_entry(ptr, head, list)
+ if (strcmp(ptr->id, id) == 0) {
+ FLT_OT_ERR("'%s' : already defined", id);
+
+ FLT_OT_RETURN_PTR(retptr);
+ }
+
+ retptr = FLT_OT_CALLOC(1, size);
+ if (retptr != NULL) {
+ retptr->id_len = strlen(id);
+ if (retptr->id_len >= FLT_OT_ID_MAXLEN)
+ FLT_OT_ERR("'%s' : name too long", id);
+ else
+ retptr->id = FLT_OT_STRDUP(id);
+
+ if (retptr->id == NULL)
+ FLT_OT_FREE_CLEAR(retptr);
+ }
+
+ if (retptr != NULL) {
+ retptr->cfg_line = linenum;
+
+ if (head != NULL)
+ LIST_APPEND(head, &(retptr->list));
+ } else {
+ FLT_OT_ERR("out of memory");
+ }
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_ph_init -
+ *
+ * ARGUMENTS
+ * id -
+ * linenum -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf_ph *flt_ot_conf_ph_init(const char *id, int linenum, struct list *head, char **err)
+{
+ struct flt_ot_conf_ph *retptr;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
+ if (retptr != NULL)
+ FLT_OT_DBG_CONF_PH("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_ph_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_ph_free(struct flt_ot_conf_ph **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF_PH("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->id);
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_sample_expr_init -
+ *
+ * ARGUMENTS
+ * id -
+ * linenum -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf_sample_expr *flt_ot_conf_sample_expr_init(const char *id, int linenum, struct list *head, char **err)
+{
+ struct flt_ot_conf_sample_expr *retptr;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
+ if (retptr != NULL)
+ FLT_OT_DBG_CONF_SAMPLE_EXPR("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_sample_expr_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_sample_expr_free(struct flt_ot_conf_sample_expr **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF_SAMPLE_EXPR("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->value);
+ release_sample_expr((*ptr)->expr);
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_sample_init -
+ *
+ * ARGUMENTS
+ * args -
+ * linenum -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf_sample *flt_ot_conf_sample_init(char **args, int linenum, struct list *head, char **err)
+{
+ struct flt_ot_conf_sample *retptr;
+
+ FLT_OT_FUNC("%p, %d, %p, %p:%p", args, linenum, head, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_conf_hdr_init(sizeof(*retptr), args[1], linenum, head, err);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ flt_ot_args_to_str(args, 2, &(retptr->value));
+ if (retptr->value == NULL) {
+ FLT_OT_FREE_CLEAR(retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+ }
+
+ retptr->num_exprs = flt_ot_args_count(args) - 2;
+ LIST_INIT(&(retptr->exprs));
+
+ FLT_OT_DBG_CONF_SAMPLE("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_sample_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_sample_free(struct flt_ot_conf_sample **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF_SAMPLE("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->key);
+ FLT_OT_FREE((*ptr)->value);
+ FLT_OT_LIST_DESTROY(sample_expr, &((*ptr)->exprs));
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_str_init -
+ *
+ * ARGUMENTS
+ * id -
+ * linenum -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf_str *flt_ot_conf_str_init(const char *id, int linenum, struct list *head, char **err)
+{
+ struct flt_ot_conf_str *retptr;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
+ if (retptr != NULL)
+ FLT_OT_DBG_CONF_STR("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_str_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_str_free(struct flt_ot_conf_str **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF_STR("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->str);
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_context_init -
+ *
+ * ARGUMENTS
+ * id -
+ * linenum -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf_context *flt_ot_conf_context_init(const char *id, int linenum, struct list *head, char **err)
+{
+ struct flt_ot_conf_context *retptr;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
+ if (retptr != NULL)
+ FLT_OT_DBG_CONF_CONTEXT("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_context_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_context_free(struct flt_ot_conf_context **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF_CONTEXT("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->id);
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_span_init -
+ *
+ * ARGUMENTS
+ * id -
+ * linenum -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf_span *flt_ot_conf_span_init(const char *id, int linenum, struct list *head, char **err)
+{
+ struct flt_ot_conf_span *retptr;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ LIST_INIT(&(retptr->tags));
+ LIST_INIT(&(retptr->logs));
+ LIST_INIT(&(retptr->baggages));
+
+ FLT_OT_DBG_CONF_SPAN("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_span_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_span_free(struct flt_ot_conf_span **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF_SPAN("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->id);
+ FLT_OT_FREE((*ptr)->ref_id);
+ FLT_OT_FREE((*ptr)->ctx_id);
+ FLT_OT_LIST_DESTROY(sample, &((*ptr)->tags));
+ FLT_OT_LIST_DESTROY(sample, &((*ptr)->logs));
+ FLT_OT_LIST_DESTROY(sample, &((*ptr)->baggages));
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_scope_init -
+ *
+ * ARGUMENTS
+ * id -
+ * linenum -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf_scope *flt_ot_conf_scope_init(const char *id, int linenum, struct list *head, char **err)
+{
+ struct flt_ot_conf_scope *retptr = NULL;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ LIST_INIT(&(retptr->acls));
+ LIST_INIT(&(retptr->contexts));
+ LIST_INIT(&(retptr->spans));
+ LIST_INIT(&(retptr->finish));
+
+ FLT_OT_DBG_CONF_SCOPE("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+/***
+ * NAME
+ * flt_ot_conf_scope_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_scope_free(struct flt_ot_conf_scope **ptr)
+{
+ struct acl *acl, *aclback;
+
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF_SCOPE("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->id);
+ list_for_each_entry_safe(acl, aclback, &((*ptr)->acls), list) {
+ prune_acl(acl);
+ FLT_OT_LIST_DEL(&(acl->list));
+ FLT_OT_FREE(acl);
+ }
+ free_acl_cond((*ptr)->cond);
+ FLT_OT_LIST_DESTROY(context, &((*ptr)->contexts));
+ FLT_OT_LIST_DESTROY(span, &((*ptr)->spans));
+ FLT_OT_LIST_DESTROY(str, &((*ptr)->finish));
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_group_init -
+ *
+ * ARGUMENTS
+ * id -
+ * linenum -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf_group *flt_ot_conf_group_init(const char *id, int linenum, struct list *head, char **err)
+{
+ struct flt_ot_conf_group *retptr;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ LIST_INIT(&(retptr->ph_scopes));
+
+ FLT_OT_DBG_CONF_GROUP("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_group_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_group_free(struct flt_ot_conf_group **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF_GROUP("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->id);
+ FLT_OT_LIST_DESTROY(ph_scope, &((*ptr)->ph_scopes));
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_tracer_init -
+ *
+ * ARGUMENTS
+ * id -
+ * linenum -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf_tracer *flt_ot_conf_tracer_init(const char *id, int linenum, char **err)
+{
+ struct flt_ot_conf_tracer *retptr;
+
+ FLT_OT_FUNC("\"%s\", %d, %p:%p", id, linenum, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, NULL, err);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ retptr->rate_limit = FLT_OT_FLOAT_U32(FLT_OT_RATE_LIMIT_MAX, FLT_OT_RATE_LIMIT_MAX);
+ init_new_proxy(&(retptr->proxy_log));
+ LIST_INIT(&(retptr->acls));
+ LIST_INIT(&(retptr->ph_groups));
+ LIST_INIT(&(retptr->ph_scopes));
+
+ FLT_OT_DBG_CONF_TRACER("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_tracer_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_tracer_free(struct flt_ot_conf_tracer **ptr)
+{
+ struct acl *acl, *aclback;
+ struct logger *logger, *loggerback;
+
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF_TRACER("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->id);
+ FLT_OT_FREE((*ptr)->config);
+ FLT_OT_FREE((*ptr)->cfgbuf);
+ FLT_OT_FREE((*ptr)->plugin);
+ FLT_OT_DBG(2, "- deleting acls list %s", flt_ot_list_debug(&((*ptr)->acls)));
+ list_for_each_entry_safe(acl, aclback, &((*ptr)->acls), list) {
+ prune_acl(acl);
+ FLT_OT_LIST_DEL(&(acl->list));
+ FLT_OT_FREE(acl);
+ }
+ FLT_OT_DBG(2, "- deleting proxy_log.loggers list %s", flt_ot_list_debug(&((*ptr)->proxy_log.loggers)));
+ list_for_each_entry_safe(logger, loggerback, &((*ptr)->proxy_log.loggers), list) {
+ LIST_DELETE(&(logger->list));
+ FLT_OT_FREE(logger);
+ }
+ FLT_OT_LIST_DESTROY(ph_group, &((*ptr)->ph_groups));
+ FLT_OT_LIST_DESTROY(ph_scope, &((*ptr)->ph_scopes));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_init -
+ *
+ * ARGUMENTS
+ * px -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_conf *flt_ot_conf_init(struct proxy *px)
+{
+ struct flt_ot_conf *retptr;
+
+ FLT_OT_FUNC("%p", px);
+
+ retptr = FLT_OT_CALLOC(1, sizeof(*retptr));
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ retptr->proxy = px;
+ LIST_INIT(&(retptr->groups));
+ LIST_INIT(&(retptr->scopes));
+
+ FLT_OT_DBG_CONF("- init ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_conf_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_conf_free(struct flt_ot_conf **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_CONF("- free ", *ptr);
+
+ FLT_OT_FREE((*ptr)->id);
+ FLT_OT_FREE((*ptr)->cfg_file);
+ flt_ot_conf_tracer_free(&((*ptr)->tracer));
+ FLT_OT_LIST_DESTROY(group, &((*ptr)->groups));
+ FLT_OT_LIST_DESTROY(scope, &((*ptr)->scopes));
+ FLT_OT_FREE_CLEAR(*ptr);
+
+ FLT_OT_RETURN();
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/event.c b/addons/ot/src/event.c
new file mode 100644
index 0000000..dc29d52
--- /dev/null
+++ b/addons/ot/src/event.c
@@ -0,0 +1,338 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+#define FLT_OT_EVENT_DEF(a,b,c,d,e,f) { AN_##b##_##a, SMP_OPT_DIR_##b, SMP_VAL_FE_##c, SMP_VAL_BE_##d, e, f },
+const struct flt_ot_event_data flt_ot_event_data[FLT_OT_EVENT_MAX] = { FLT_OT_EVENT_DEFINES };
+#undef FLT_OT_EVENT_DEF
+
+
+/***
+ * NAME
+ * flt_ot_scope_run_span -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * chn -
+ * dir -
+ * span -
+ * data -
+ * conf_span -
+ * ts -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+static int flt_ot_scope_run_span(struct stream *s, struct filter *f, struct channel *chn, uint dir, struct flt_ot_scope_span *span, struct flt_ot_scope_data *data, const struct flt_ot_conf_span *conf_span, const struct timespec *ts, char **err)
+{
+ struct flt_ot_conf *conf = FLT_OT_CONF(f);
+ int retval = FLT_OT_RET_OK;
+
+ FLT_OT_FUNC("%p, %p, %p, %u, %p, %p, %p, %p, %p:%p", s, f, chn, dir, span, data, conf_span, ts, FLT_OT_DPTR_ARGS(err));
+
+ if (span == NULL)
+ FLT_OT_RETURN_INT(retval);
+
+ if (span->span == NULL) {
+ span->span = ot_span_init(conf->tracer->tracer, span->id, ts, NULL, span->ref_type, FLT_OT_DEREF(span->ref_ctx, idx, -1), span->ref_span, data->tags, data->num_tags, err);
+ if (span->span == NULL)
+ retval = FLT_OT_RET_ERROR;
+ }
+ else if (data->num_tags > 0)
+ if (ot_span_tag(span->span, data->tags, data->num_tags) == -1)
+ retval = FLT_OT_RET_ERROR;
+
+ if ((span->span != NULL) && (data->baggage != NULL))
+ if (ot_span_set_baggage(span->span, data->baggage) == -1)
+ retval = FLT_OT_RET_ERROR;
+
+ if ((span->span != NULL) && (data->num_log_fields > 0))
+ if (ot_span_log(span->span, data->log_fields, data->num_log_fields) == -1)
+ retval = FLT_OT_RET_ERROR;
+
+ if ((span->span != NULL) && (conf_span->ctx_id != NULL)) {
+ struct otc_http_headers_writer writer;
+ struct otc_text_map *text_map = NULL;
+ struct otc_span_context *span_ctx;
+
+ span_ctx = ot_inject_http_headers(conf->tracer->tracer, span->span, &writer, err);
+ if (span_ctx != NULL) {
+ int i = 0;
+
+ if (conf_span->ctx_flags & (FLT_OT_CTX_USE_VARS | FLT_OT_CTX_USE_HEADERS)) {
+ for (text_map = &(writer.text_map); i < text_map->count; i++) {
+#ifdef USE_OT_VARS
+ if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_VARS))
+ /* Do nothing. */;
+ else if (flt_ot_var_register(FLT_OT_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], err) == -1)
+ retval = FLT_OT_RET_ERROR;
+ else if (flt_ot_var_set(s, FLT_OT_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], text_map->value[i], dir, err) == -1)
+ retval = FLT_OT_RET_ERROR;
+#endif
+
+ if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_HEADERS))
+ /* Do nothing. */;
+ else if (flt_ot_http_header_set(chn, conf_span->ctx_id, text_map->key[i], text_map->value[i], err) == -1)
+ retval = FLT_OT_RET_ERROR;
+ }
+ }
+
+ span_ctx->destroy(&span_ctx);
+ otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
+ }
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_scope_run -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * chn -
+ * conf_scope -
+ * ts -
+ * dir -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+int flt_ot_scope_run(struct stream *s, struct filter *f, struct channel *chn, struct flt_ot_conf_scope *conf_scope, const struct timespec *ts, uint dir, char **err)
+{
+ struct flt_ot_conf *conf = FLT_OT_CONF(f);
+ struct flt_ot_conf_context *conf_ctx;
+ struct flt_ot_conf_span *conf_span;
+ struct flt_ot_conf_str *finish;
+ struct timespec ts_now;
+ int retval = FLT_OT_RET_OK;
+
+ FLT_OT_FUNC("%p, %p, %p, %p, %p, %u, %p:%p", s, f, chn, conf_scope, ts, dir, FLT_OT_DPTR_ARGS(err));
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
+ FLT_OT_DBG(3, "run scope '%s' %d", conf_scope->id, conf_scope->event);
+ FLT_OT_DBG_CONF_SCOPE("run scope ", conf_scope);
+
+ if (ts == NULL) {
+ (void)clock_gettime(CLOCK_MONOTONIC, &ts_now);
+
+ ts = &ts_now;
+ }
+
+ if (conf_scope->cond != NULL) {
+ enum acl_test_res res;
+ int rc;
+
+ res = acl_exec_cond(conf_scope->cond, s->be, s->sess, s, dir | SMP_OPT_FINAL);
+ rc = acl_pass(res);
+ if (conf_scope->cond->pol == ACL_COND_UNLESS)
+ rc = !rc;
+
+ FLT_OT_DBG(3, "the ACL rule %s", rc ? "matches" : "does not match");
+
+ /*
+ * If the rule does not match, the current scope is skipped.
+ *
+ * If it is a root span, further processing of the session is
+ * disabled. As soon as the first span is encountered which
+ * is marked as root, further search is interrupted.
+ */
+ if (!rc) {
+ list_for_each_entry(conf_span, &(conf_scope->spans), list)
+ if (conf_span->flag_root) {
+ FLT_OT_DBG(0, "session disabled");
+
+ FLT_OT_RT_CTX(f->ctx)->flag_disabled = 1;
+
+ _HA_ATOMIC_ADD(conf->cnt.disabled + 0, 1);
+
+ break;
+ }
+
+ FLT_OT_RETURN_INT(retval);
+ }
+ }
+
+ list_for_each_entry(conf_ctx, &(conf_scope->contexts), list) {
+ struct otc_text_map *text_map = NULL;
+
+ FLT_OT_DBG(3, "run context '%s' -> '%s'", conf_scope->id, conf_ctx->id);
+ FLT_OT_DBG_CONF_CONTEXT("run context ", conf_ctx);
+
+ /*
+ * The OpenTracing context is read from the HTTP header
+ * or from HAProxy variables.
+ */
+ if (conf_ctx->flags & FLT_OT_CTX_USE_HEADERS)
+ text_map = flt_ot_http_headers_get(chn, conf_ctx->id, conf_ctx->id_len, err);
+#ifdef USE_OT_VARS
+ else
+ text_map = flt_ot_vars_get(s, FLT_OT_VARS_SCOPE, conf_ctx->id, dir, err);
+#endif
+
+ if (text_map != NULL) {
+ if (flt_ot_scope_context_init(f->ctx, conf->tracer->tracer, conf_ctx->id, conf_ctx->id_len, text_map, dir, err) == NULL)
+ retval = FLT_OT_RET_ERROR;
+
+ otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
+ } else {
+ retval = FLT_OT_RET_ERROR;
+ }
+ }
+
+ list_for_each_entry(conf_span, &(conf_scope->spans), list) {
+ struct flt_ot_scope_data data;
+ struct flt_ot_scope_span *span;
+ struct flt_ot_conf_sample *sample;
+
+ FLT_OT_DBG(3, "run span '%s' -> '%s'", conf_scope->id, conf_span->id);
+ FLT_OT_DBG_CONF_SPAN("run span ", conf_span);
+
+ (void)memset(&data, 0, sizeof(data));
+
+ span = flt_ot_scope_span_init(f->ctx, conf_span->id, conf_span->id_len, conf_span->ref_type, conf_span->ref_id, conf_span->ref_id_len, dir, err);
+ if (span == NULL)
+ retval = FLT_OT_RET_ERROR;
+
+ list_for_each_entry(sample, &(conf_span->tags), list) {
+ FLT_OT_DBG(3, "adding tag '%s' -> '%s'", sample->key, sample->value);
+
+ if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_TAG, err) == FLT_OT_RET_ERROR)
+ retval = FLT_OT_RET_ERROR;
+ }
+
+ list_for_each_entry(sample, &(conf_span->logs), list) {
+ FLT_OT_DBG(3, "adding log '%s' -> '%s'", sample->key, sample->value);
+
+ if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_LOG, err) == FLT_OT_RET_ERROR)
+ retval = FLT_OT_RET_ERROR;
+ }
+
+ list_for_each_entry(sample, &(conf_span->baggages), list) {
+ FLT_OT_DBG(3, "adding baggage '%s' -> '%s'", sample->key, sample->value);
+
+ if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_BAGGAGE, err) == FLT_OT_RET_ERROR)
+ retval = FLT_OT_RET_ERROR;
+ }
+
+ if (retval != FLT_OT_RET_ERROR)
+ if (flt_ot_scope_run_span(s, f, chn, dir, span, &data, conf_span, ts, err) == FLT_OT_RET_ERROR)
+ retval = FLT_OT_RET_ERROR;
+
+ flt_ot_scope_data_free(&data);
+ }
+
+ list_for_each_entry(finish, &(conf_scope->finish), list)
+ if (flt_ot_scope_finish_mark(f->ctx, finish->str, finish->str_len) == -1)
+ retval = FLT_OT_RET_ERROR;
+
+ flt_ot_scope_finish_marked(f->ctx, ts);
+ flt_ot_scope_free_unused(f->ctx, chn);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_event_run -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * chn -
+ * event -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+int flt_ot_event_run(struct stream *s, struct filter *f, struct channel *chn, int event, char **err)
+{
+ struct flt_ot_conf *conf = FLT_OT_CONF(f);
+ struct flt_ot_conf_scope *conf_scope;
+ struct timespec ts;
+ int retval = FLT_OT_RET_OK;
+
+ FLT_OT_FUNC("%p, %p, %p, %d, %p:%p", s, f, chn, event, FLT_OT_DPTR_ARGS(err));
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
+ FLT_OT_DBG(3, "run event '%s' %d", flt_ot_event_data[event].name, event);
+
+#ifdef DEBUG_OT
+ _HA_ATOMIC_ADD(conf->cnt.event[event].htx + (htx_is_empty(htxbuf(&(chn->buf))) ? 1 : 0), 1);
+#endif
+
+ FLT_OT_RT_CTX(f->ctx)->analyzers |= flt_ot_event_data[event].an_bit;
+
+ /* All spans should be created/completed at the same time. */
+ (void)clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ /*
+ * It is possible that there are defined multiple scopes that use the
+ * same event. Therefore, there must not be a 'break' here, ie an
+ * exit from the 'for' loop.
+ */
+ list_for_each_entry(conf_scope, &(conf->scopes), list) {
+ if (conf_scope->event != event)
+ /* Do nothing. */;
+ else if (!conf_scope->flag_used)
+ FLT_OT_DBG(3, "scope '%s' %d not used", conf_scope->id, conf_scope->event);
+ else if (flt_ot_scope_run(s, f, chn, conf_scope, &ts, flt_ot_event_data[event].smp_opt_dir, err) == FLT_OT_RET_ERROR)
+ retval = FLT_OT_RET_ERROR;
+ }
+
+#ifdef USE_OT_VARS
+ flt_ot_vars_dump(s);
+#endif
+ flt_ot_http_headers_dump(chn);
+
+ FLT_OT_DBG(3, "event = %d, chn = %p, s->req = %p, s->res = %p", event, chn, &(s->req), &(s->res));
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/filter.c b/addons/ot/src/filter.c
new file mode 100644
index 0000000..cf67fd2
--- /dev/null
+++ b/addons/ot/src/filter.c
@@ -0,0 +1,1176 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+/*
+ * OpenTracing filter id, used to identify OpenTracing filters.
+ * The name of this variable is consistent with the other filter names
+ * declared in include/haproxy/filters.h .
+ */
+const char *ot_flt_id = "the OpenTracing filter";
+
+
+/***
+ * NAME
+ * flt_ot_is_disabled -
+ *
+ * ARGUMENTS
+ * f -
+ * event -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+bool flt_ot_is_disabled(const struct filter *f FLT_OT_DBG_ARGS(, int event))
+{
+#ifdef DEBUG_OT
+ const struct flt_ot_conf *conf = FLT_OT_CONF(f);
+ const char *msg;
+#endif
+ bool retval;
+
+ retval = FLT_OT_RT_CTX(f->ctx)->flag_disabled ? 1 : 0;
+
+#ifdef DEBUG_OT
+ msg = retval ? " (disabled)" : "";
+
+ if (FLT_OT_IN_RANGE(event, 0, FLT_OT_EVENT_MAX - 1))
+ FLT_OT_DBG(2, "filter '%s', type: %s, event: '%s' %d%s", conf->id, flt_ot_type(f), flt_ot_event_data[event].name, event, msg);
+ else
+ FLT_OT_DBG(2, "filter '%s', type: %s%s", conf->id, flt_ot_type(f), msg);
+#endif
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * flt_ot_return_int -
+ *
+ * ARGUMENTS
+ * f -
+ * err -
+ * retval -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_return_int(const struct filter *f, char **err, int retval)
+{
+ struct flt_ot_runtime_context *rt_ctx = f->ctx;
+
+ if ((retval == FLT_OT_RET_ERROR) || ((err != NULL) && (*err != NULL))) {
+ if (rt_ctx->flag_harderr) {
+ FLT_OT_DBG(1, "WARNING: filter hard-error (disabled)");
+
+ rt_ctx->flag_disabled = 1;
+
+ _HA_ATOMIC_ADD(FLT_OT_CONF(f)->cnt.disabled + 1, 1);
+ } else {
+ FLT_OT_DBG(1, "WARNING: filter soft-error");
+ }
+
+ retval = FLT_OT_RET_OK;
+ }
+
+ FLT_OT_ERR_FREE(*err);
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * flt_ot_return_void -
+ *
+ * ARGUMENTS
+ * f -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_return_void(const struct filter *f, char **err)
+{
+ struct flt_ot_runtime_context *rt_ctx = f->ctx;
+
+ if ((err != NULL) && (*err != NULL)) {
+ if (rt_ctx->flag_harderr) {
+ FLT_OT_DBG(1, "WARNING: filter hard-error (disabled)");
+
+ rt_ctx->flag_disabled = 1;
+
+ _HA_ATOMIC_ADD(FLT_OT_CONF(f)->cnt.disabled + 1, 1);
+ } else {
+ FLT_OT_DBG(1, "WARNING: filter soft-error");
+ }
+ }
+
+ FLT_OT_ERR_FREE(*err);
+}
+
+
+/***
+ * NAME
+ * flt_ot_init - Initialize the filter.
+ *
+ * ARGUMENTS
+ * p -
+ * fconf -
+ *
+ * DESCRIPTION
+ * It initializes the filter for a proxy. You may define this callback
+ * if you need to complete your filter configuration.
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, any other value otherwise.
+ */
+static int flt_ot_init(struct proxy *p, struct flt_conf *fconf)
+{
+ struct flt_ot_conf *conf = FLT_OT_DEREF(fconf, conf, NULL);
+ char *err = NULL;
+ int retval = FLT_OT_RET_ERROR;
+
+ FLT_OT_FUNC("%p, %p", p, fconf);
+
+ if (conf == NULL)
+ FLT_OT_RETURN_INT(retval);
+
+ flt_ot_cli_init();
+
+ /*
+ * Initialize the OpenTracing library.
+ */
+ retval = ot_init(&(conf->tracer->tracer), conf->tracer->plugin, &err);
+ if (retval != FLT_OT_RET_ERROR)
+ /* Do nothing. */;
+ else if (err != NULL) {
+ FLT_OT_ALERT("%s", err);
+
+ FLT_OT_ERR_FREE(err);
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_deinit - Free resources allocated by the filter.
+ *
+ * ARGUMENTS
+ * p -
+ * fconf -
+ *
+ * DESCRIPTION
+ * It cleans up what the parsing function and the init callback have done.
+ * This callback is useful to release memory allocated for the filter
+ * configuration.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_deinit(struct proxy *p, struct flt_conf *fconf)
+{
+ struct flt_ot_conf **conf = (fconf == NULL) ? NULL : (typeof(conf))&(fconf->conf);
+#ifdef DEBUG_OT
+ int i;
+#endif
+
+ FLT_OT_FUNC("%p, %p", p, fconf);
+
+ if (conf == NULL)
+ FLT_OT_RETURN();
+
+ ot_debug();
+ ot_close(&((*conf)->tracer->tracer));
+
+#ifdef DEBUG_OT
+ FLT_OT_DBG(0, "--- used events ----------");
+ for (i = 0; i < FLT_OT_TABLESIZE((*conf)->cnt.event); i++)
+ if ((*conf)->cnt.event[i].flag_used)
+ FLT_OT_DBG(0, " %02d: %" PRIu64 " / %" PRIu64, i, (*conf)->cnt.event[i].htx[0], (*conf)->cnt.event[i].htx[1]);
+#endif
+
+ flt_ot_conf_free(conf);
+
+ FLT_OT_MEMINFO();
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_check - Check configuration of the filter for the specified proxy.
+ *
+ * ARGUMENTS
+ * p -
+ * fconf -
+ *
+ * DESCRIPTION
+ * Optionally, by implementing the flt_ot_check() callback, you add a
+ * step to check the internal configuration of your filter after the
+ * parsing phase, when the HAProxy configuration is fully defined.
+ *
+ * RETURN VALUE
+ * Returns the number of encountered errors.
+ */
+static int flt_ot_check(struct proxy *p, struct flt_conf *fconf)
+{
+ struct proxy *px;
+ struct flt_ot_conf *conf = FLT_OT_DEREF(fconf, conf, NULL);
+ struct flt_ot_conf_group *conf_group;
+ struct flt_ot_conf_scope *conf_scope;
+ struct flt_ot_conf_ph *ph_group, *ph_scope;
+ int retval = 0, scope_unused_cnt = 0, span_root_cnt = 0;
+
+ FLT_OT_FUNC("%p, %p", p, fconf);
+
+ if (conf == NULL)
+ FLT_OT_RETURN_INT(++retval);
+
+ /*
+ * If only the proxy specified with the <p> parameter is checked, then
+ * no duplicate filters can be found that are not defined in the same
+ * configuration sections.
+ */
+ for (px = proxies_list; px != NULL; px = px->next) {
+ struct flt_conf *fconf_tmp;
+
+ FLT_OT_DBG(2, "proxy '%s'", px->id);
+
+ /*
+ * The names of all OT filters (filter ID) should be checked,
+ * they must be unique.
+ */
+ list_for_each_entry(fconf_tmp, &(px->filter_configs), list)
+ if ((fconf_tmp != fconf) && (fconf_tmp->id == ot_flt_id)) {
+ struct flt_ot_conf *conf_tmp = fconf_tmp->conf;
+
+ FLT_OT_DBG(2, " OT filter '%s'", conf_tmp->id);
+
+ if (strcmp(conf_tmp->id, conf->id) == 0) {
+ FLT_OT_ALERT("''%s' : duplicated filter ID'", conf_tmp->id);
+
+ retval++;
+ }
+ }
+ }
+
+ if (FLT_OT_DEREF(conf->tracer, id, NULL) == NULL) {
+ FLT_OT_ALERT("''%s' : no tracer found'", conf->id);
+
+ retval++;
+ }
+
+ /*
+ * Checking that all defined 'ot-group' sections have correctly declared
+ * 'ot-scope' sections (ie whether the declared 'ot-scope' sections have
+ * corresponding definitions).
+ */
+ list_for_each_entry(conf_group, &(conf->groups), list)
+ list_for_each_entry(ph_scope, &(conf_group->ph_scopes), list) {
+ bool flag_found = 0;
+
+ list_for_each_entry(conf_scope, &(conf->scopes), list)
+ if (strcmp(ph_scope->id, conf_scope->id) == 0) {
+ ph_scope->ptr = conf_scope;
+ conf_scope->flag_used = 1;
+ flag_found = 1;
+
+ break;
+ }
+
+ if (!flag_found) {
+ FLT_OT_ALERT("'" FLT_OT_PARSE_SECTION_GROUP_ID " '%s' : try to use undefined " FLT_OT_PARSE_SECTION_SCOPE_ID " '%s''", conf_group->id, ph_scope->id);
+
+ retval++;
+ }
+ }
+
+ if (conf->tracer != NULL) {
+ /*
+ * Checking that all declared 'groups' keywords have correctly
+ * defined 'ot-group' sections.
+ */
+ list_for_each_entry(ph_group, &(conf->tracer->ph_groups), list) {
+ bool flag_found = 0;
+
+ list_for_each_entry(conf_group, &(conf->groups), list)
+ if (strcmp(ph_group->id, conf_group->id) == 0) {
+ ph_group->ptr = conf_group;
+ conf_group->flag_used = 1;
+ flag_found = 1;
+
+ break;
+ }
+
+ if (!flag_found) {
+ FLT_OT_ALERT("'" FLT_OT_PARSE_SECTION_TRACER_ID " '%s' : try to use undefined " FLT_OT_PARSE_SECTION_GROUP_ID " '%s''", conf->tracer->id, ph_group->id);
+
+ retval++;
+ }
+ }
+
+ /*
+ * Checking that all declared 'scopes' keywords have correctly
+ * defined 'ot-scope' sections.
+ */
+ list_for_each_entry(ph_scope, &(conf->tracer->ph_scopes), list) {
+ bool flag_found = 0;
+
+ list_for_each_entry(conf_scope, &(conf->scopes), list)
+ if (strcmp(ph_scope->id, conf_scope->id) == 0) {
+ ph_scope->ptr = conf_scope;
+ conf_scope->flag_used = 1;
+ flag_found = 1;
+
+ break;
+ }
+
+ if (!flag_found) {
+ FLT_OT_ALERT("'" FLT_OT_PARSE_SECTION_TRACER_ID " '%s' : try to use undefined " FLT_OT_PARSE_SECTION_SCOPE_ID " '%s''", conf->tracer->id, ph_scope->id);
+
+ retval++;
+ }
+ }
+ }
+
+ FLT_OT_DBG(3, "--- filter '%s' configuration ----------", conf->id);
+ FLT_OT_DBG(3, "- defined spans ----------");
+
+ list_for_each_entry(conf_scope, &(conf->scopes), list) {
+ if (conf_scope->flag_used) {
+ struct flt_ot_conf_span *conf_span;
+
+ /*
+ * In principle, only one span should be labeled
+ * as a root span.
+ */
+ list_for_each_entry(conf_span, &(conf_scope->spans), list) {
+ FLT_OT_DBG_CONF_SPAN(" ", conf_span);
+
+ span_root_cnt += conf_span->flag_root ? 1 : 0;
+ }
+
+#ifdef DEBUG_OT
+ conf->cnt.event[conf_scope->event].flag_used = 1;
+#endif
+
+ /* Set the flags of the analyzers used. */
+ conf->tracer->analyzers |= flt_ot_event_data[conf_scope->event].an_bit;
+ } else {
+ FLT_OT_ALERT("''%s' : unused " FLT_OT_PARSE_SECTION_SCOPE_ID " '%s''", conf->id, conf_scope->id);
+
+ scope_unused_cnt++;
+ }
+ }
+
+ /*
+ * Unused scopes or a number of root spans other than one do not
+ * necessarily have to be errors, but it is good to print it when
+ * starting HAProxy.
+ */
+ if (scope_unused_cnt > 0)
+ FLT_OT_ALERT("''%s' : %d scope(s) not in use'", conf->id, scope_unused_cnt);
+
+ if (LIST_ISEMPTY(&(conf->scopes)))
+ /* Do nothing. */;
+ else if (span_root_cnt == 0)
+ FLT_OT_ALERT("''%s' : no span is marked as the root span'", conf->id);
+ else if (span_root_cnt > 1)
+ FLT_OT_ALERT("''%s' : multiple spans are marked as the root span'", conf->id);
+
+ FLT_OT_DBG_LIST(conf, group, "", "defined", _group,
+ FLT_OT_DBG_CONF_GROUP(" ", _group);
+ FLT_OT_DBG_LIST(_group, ph_scope, " ", "used", _scope, FLT_OT_DBG_CONF_PH(" ", _scope)));
+ FLT_OT_DBG_LIST(conf, scope, "", "defined", _scope, FLT_OT_DBG_CONF_SCOPE(" ", _scope));
+
+ if (conf->tracer != NULL) {
+ FLT_OT_DBG(3, " --- tracer '%s' configuration ----------", conf->tracer->id);
+ FLT_OT_DBG_LIST(conf->tracer, ph_group, " ", "used", _group, FLT_OT_DBG_CONF_PH(" ", _group));
+ FLT_OT_DBG_LIST(conf->tracer, ph_scope, " ", "used", _scope, FLT_OT_DBG_CONF_PH(" ", _scope));
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_init_per_thread -
+ *
+ * ARGUMENTS
+ * p -
+ * fconf -
+ *
+ * DESCRIPTION
+ * It initializes the filter for each thread. It works the same way than
+ * flt_ot_init() but in the context of a thread. This callback is called
+ * after the thread creation.
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, any other value otherwise.
+ */
+static int flt_ot_init_per_thread(struct proxy *p, struct flt_conf *fconf)
+{
+ struct flt_ot_conf *conf = FLT_OT_DEREF(fconf, conf, NULL);
+ char *err = NULL;
+ int retval = FLT_OT_RET_ERROR;
+
+ FLT_OT_FUNC("%p, %p", p, fconf);
+
+ if (conf == NULL)
+ FLT_OT_RETURN_INT(retval);
+
+ /*
+ * Start the OpenTracing library tracer thread.
+ * Enable HTX streams filtering.
+ */
+ if (!(fconf->flags & FLT_CFG_FL_HTX)) {
+ retval = ot_start(conf->tracer->tracer, conf->tracer->cfgbuf, &err);
+ if (retval != FLT_OT_RET_ERROR)
+ fconf->flags |= FLT_CFG_FL_HTX;
+ else if (err != NULL) {
+ FLT_OT_ALERT("%s", err);
+
+ FLT_OT_ERR_FREE(err);
+ }
+ } else {
+ retval = FLT_OT_RET_OK;
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+#ifdef DEBUG_OT
+
+/***
+ * NAME
+ * flt_ot_deinit_per_thread -
+ *
+ * ARGUMENTS
+ * p -
+ * fconf -
+ *
+ * DESCRIPTION
+ * It cleans up what the init_per_thread callback have done. It is called
+ * in the context of a thread, before exiting it.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_deinit_per_thread(struct proxy *p, struct flt_conf *fconf)
+{
+ FLT_OT_FUNC("%p, %p", p, fconf);
+
+ FLT_OT_RETURN();
+}
+
+#endif /* DEBUG_OT */
+
+
+/***
+ * NAME
+ * flt_ot_attach - Called when a filter instance is created and attach to a stream.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ *
+ * DESCRIPTION
+ * It is called after a filter instance creation, when it is attached to a
+ * stream. This happens when the stream is started for filters defined on
+ * the stream's frontend and when the backend is set for filters declared
+ * on the stream's backend. It is possible to ignore the filter, if needed,
+ * by returning 0. This could be useful to have conditional filtering.
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 to ignore the filter,
+ * any other value otherwise.
+ */
+static int flt_ot_attach(struct stream *s, struct filter *f)
+{
+ const struct flt_ot_conf *conf = FLT_OT_CONF(f);
+ char *err = NULL;
+
+ FLT_OT_FUNC("%p, %p", s, f);
+
+ if (conf->tracer->flag_disabled) {
+ FLT_OT_DBG(2, "filter '%s', type: %s (disabled)", conf->id, flt_ot_type(f));
+
+ FLT_OT_RETURN_INT(FLT_OT_RET_IGNORE);
+ }
+ else if (conf->tracer->rate_limit < FLT_OT_FLOAT_U32(FLT_OT_RATE_LIMIT_MAX, FLT_OT_RATE_LIMIT_MAX)) {
+ uint32_t rnd = ha_random32();
+
+ if (conf->tracer->rate_limit <= rnd) {
+ FLT_OT_DBG(2, "filter '%s', type: %s (ignored: %u <= %u)", conf->id, flt_ot_type(f), conf->tracer->rate_limit, rnd);
+
+ FLT_OT_RETURN_INT(FLT_OT_RET_IGNORE);
+ }
+ }
+
+ FLT_OT_DBG(2, "filter '%s', type: %s (run)", conf->id, flt_ot_type(f));
+
+ f->ctx = flt_ot_runtime_context_init(s, f, &err);
+ FLT_OT_ERR_FREE(err);
+ if (f->ctx == NULL) {
+ FLT_OT_LOG(LOG_EMERG, "failed to create context");
+
+ FLT_OT_RETURN_INT(FLT_OT_RET_IGNORE);
+ }
+
+ /*
+ * AN_REQ_WAIT_HTTP and AN_RES_WAIT_HTTP analyzers can only be used
+ * in the .channel_post_analyze callback function.
+ */
+ f->pre_analyzers |= conf->tracer->analyzers & ((AN_REQ_ALL & ~AN_REQ_WAIT_HTTP & ~AN_REQ_HTTP_TARPIT) | (AN_RES_ALL & ~AN_RES_WAIT_HTTP));
+ f->post_analyzers |= conf->tracer->analyzers & (AN_REQ_WAIT_HTTP | AN_RES_WAIT_HTTP);
+
+ FLT_OT_LOG(LOG_INFO, "%08x %08x", f->pre_analyzers, f->post_analyzers);
+
+#ifdef USE_OT_VARS
+ flt_ot_vars_dump(s);
+#endif
+ flt_ot_http_headers_dump(&(s->req));
+
+ FLT_OT_RETURN_INT(FLT_OT_RET_OK);
+}
+
+
+#ifdef DEBUG_OT
+
+/***
+ * NAME
+ * flt_ot_stream_start - Called when a stream is created.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ *
+ * DESCRIPTION
+ * It is called when a stream is started. This callback can fail by
+ * returning a negative value. It will be considered as a critical error
+ * by HAProxy which disabled the listener for a short time.
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, any other value otherwise.
+ */
+static int flt_ot_stream_start(struct stream *s, struct filter *f)
+{
+ char *err = NULL;
+ int retval = FLT_OT_RET_OK;
+
+ FLT_OT_FUNC("%p, %p", s, f);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN_INT(retval);
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+
+/***
+ * NAME
+ * flt_ot_stream_set_backend - Called when a backend is set for a stream.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * be -
+ *
+ * DESCRIPTION
+ * It is called when a backend is set for a stream. This callbacks will be
+ * called for all filters attached to a stream (frontend and backend). Note
+ * this callback is not called if the frontend and the backend are the same.
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, any other value otherwise.
+ */
+static int flt_ot_stream_set_backend(struct stream *s, struct filter *f, struct proxy *be)
+{
+ char *err = NULL;
+ int retval = FLT_OT_RET_OK;
+
+ FLT_OT_FUNC("%p, %p, %p", s, f, be);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN_INT(retval);
+
+ FLT_OT_DBG(3, "backend: %s", be->id);
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+
+/***
+ * NAME
+ * flt_ot_stream_stop - Called when a stream is destroyed.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ *
+ * DESCRIPTION
+ * It is called when a stream is stopped. This callback always succeed.
+ * Anyway, it is too late to return an error.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_stream_stop(struct stream *s, struct filter *f)
+{
+ char *err = NULL;
+
+ FLT_OT_FUNC("%p, %p", s, f);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN();
+
+ flt_ot_return_void(f, &err);
+
+ FLT_OT_RETURN();
+}
+
+#endif /* DEBUG_OT */
+
+
+/***
+ * NAME
+ * flt_ot_detach - Called when a filter instance is detach from a stream, just before its destruction.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ *
+ * DESCRIPTION
+ * It is called when a filter instance is detached from a stream, before its
+ * destruction. This happens when the stream is stopped for filters defined
+ * on the stream's frontend and when the analyze ends for filters defined on
+ * the stream's backend.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_detach(struct stream *s, struct filter *f)
+{
+ FLT_OT_FUNC("%p, %p", s, f);
+
+ FLT_OT_DBG(2, "filter '%s', type: %s", FLT_OT_CONF(f)->id, flt_ot_type(f));
+
+ flt_ot_runtime_context_free(f);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_check_timeouts - Called when a stream is woken up because of an expired timer.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_check_timeouts(struct stream *s, struct filter *f)
+{
+ char *err = NULL;
+
+ FLT_OT_FUNC("%p, %p", s, f);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN();
+
+ s->pending_events |= TASK_WOKEN_MSG;
+
+ flt_ot_return_void(f, &err);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_channel_start_analyze - Called when analyze starts for a given channel.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * chn -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+static int flt_ot_channel_start_analyze(struct stream *s, struct filter *f, struct channel *chn)
+{
+ char *err = NULL;
+ int retval;
+
+ FLT_OT_FUNC("%p, %p, %p", s, f, chn);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, (chn->flags & CF_ISRESP) ? FLT_OT_EVENT_RES_SERVER_SESS_START : FLT_OT_EVENT_REQ_CLIENT_SESS_START)))
+ FLT_OT_RETURN_INT(FLT_OT_RET_OK);
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
+
+ if (chn->flags & CF_ISRESP) {
+ /* The response channel. */
+ chn->analysers |= f->pre_analyzers & AN_RES_ALL;
+
+ /* The event 'on-server-session-start'. */
+ retval = flt_ot_event_run(s, f, chn, FLT_OT_EVENT_RES_SERVER_SESS_START, &err);
+ if (retval == FLT_OT_RET_WAIT) {
+ channel_dont_read(chn);
+ channel_dont_close(chn);
+ }
+ } else {
+ /* The request channel. */
+ chn->analysers |= f->pre_analyzers & AN_REQ_ALL;
+
+ /* The event 'on-client-session-start'. */
+ retval = flt_ot_event_run(s, f, chn, FLT_OT_EVENT_REQ_CLIENT_SESS_START, &err);
+ }
+
+// register_data_filter(s, chn, f);
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+
+/***
+ * NAME
+ * flt_ot_channel_pre_analyze - Called before a processing happens on a given channel.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * chn - the channel on which the analyzing is done
+ * an_bit - the analyzer id
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+static int flt_ot_channel_pre_analyze(struct stream *s, struct filter *f, struct channel *chn, uint an_bit)
+{
+ char *err = NULL;
+ int i, event = -1, retval;
+
+ FLT_OT_FUNC("%p, %p, %p, 0x%08x", s, f, chn, an_bit);
+
+ for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_event_data); i++)
+ if (flt_ot_event_data[i].an_bit == an_bit) {
+ event = i;
+
+ break;
+ }
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, event)))
+ FLT_OT_RETURN_INT(FLT_OT_RET_OK);
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s), analyzer: %s", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s), flt_ot_analyzer(an_bit));
+
+ retval = flt_ot_event_run(s, f, chn, event, &err);
+
+ if ((retval == FLT_OT_RET_WAIT) && (chn->flags & CF_ISRESP)) {
+ channel_dont_read(chn);
+ channel_dont_close(chn);
+ }
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+
+/***
+ * NAME
+ * flt_ot_channel_post_analyze - Called after a processing happens on a given channel.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * chn -
+ * an_bit -
+ *
+ * DESCRIPTION
+ * This function, for its part, is not resumable. It is called when a
+ * filterable analyzer finishes its processing. So it called once for
+ * the same analyzer.
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+static int flt_ot_channel_post_analyze(struct stream *s, struct filter *f, struct channel *chn, uint an_bit)
+{
+ char *err = NULL;
+ int i, event = -1, retval;
+
+ FLT_OT_FUNC("%p, %p, %p, 0x%08x", s, f, chn, an_bit);
+
+ for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_event_data); i++)
+ if (flt_ot_event_data[i].an_bit == an_bit) {
+ event = i;
+
+ break;
+ }
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, event)))
+ FLT_OT_RETURN_INT(FLT_OT_RET_OK);
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s), analyzer: %s", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s), flt_ot_analyzer(an_bit));
+
+ retval = flt_ot_event_run(s, f, chn, event, &err);
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+
+/***
+ * NAME
+ * flt_ot_channel_end_analyze - Called when analyze ends for a given channel.
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * chn -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+static int flt_ot_channel_end_analyze(struct stream *s, struct filter *f, struct channel *chn)
+{
+ char *err = NULL;
+ int rc, retval;
+
+ FLT_OT_FUNC("%p, %p, %p", s, f, chn);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, (chn->flags & CF_ISRESP) ? FLT_OT_EVENT_RES_SERVER_SESS_END : FLT_OT_EVENT_REQ_CLIENT_SESS_END)))
+ FLT_OT_RETURN_INT(FLT_OT_RET_OK);
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
+
+ if (chn->flags & CF_ISRESP) {
+ /* The response channel, event 'on-server-session-end'. */
+ retval = flt_ot_event_run(s, f, chn, FLT_OT_EVENT_RES_SERVER_SESS_END, &err);
+ } else {
+ /* The request channel, event 'on-client-session-end'. */
+ retval = flt_ot_event_run(s, f, chn, FLT_OT_EVENT_REQ_CLIENT_SESS_END, &err);
+
+ /*
+ * In case an event using server response is defined and not
+ * executed, event 'on-server-unavailable' is called here.
+ */
+ if ((FLT_OT_CONF(f)->tracer->analyzers & AN_RES_ALL) && !(FLT_OT_RT_CTX(f->ctx)->analyzers & AN_RES_ALL)) {
+ rc = flt_ot_event_run(s, f, chn, FLT_OT_EVENT_REQ_SERVER_UNAVAILABLE, &err);
+ if ((retval == FLT_OT_RET_OK) && (rc != FLT_OT_RET_OK))
+ retval = rc;
+ }
+ }
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+
+#ifdef DEBUG_OT
+
+/***
+ * NAME
+ * flt_ot_http_headers -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * msg -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+static int flt_ot_http_headers(struct stream *s, struct filter *f, struct http_msg *msg)
+{
+ char *err = NULL;
+ struct htx *htx = htxbuf(&(msg->chn->buf));
+ struct htx_sl *sl = http_get_stline(htx);
+ int retval = FLT_OT_RET_OK;
+
+ FLT_OT_FUNC("%p, %p, %p", s, f, msg);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN_INT(retval);
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s), %.*s %.*s %.*s", flt_ot_chn_label(msg->chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s), HTX_SL_P1_LEN(sl), HTX_SL_P1_PTR(sl), HTX_SL_P2_LEN(sl), HTX_SL_P2_PTR(sl), HTX_SL_P3_LEN(sl), HTX_SL_P3_PTR(sl));
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+
+/***
+ * NAME
+ * flt_ot_http_payload -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * msg -
+ * offset -
+ * len -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, any other value otherwise.
+ */
+static int flt_ot_http_payload(struct stream *s, struct filter *f, struct http_msg *msg, uint offset, uint len)
+{
+ char *err = NULL;
+ int retval = len;
+
+ FLT_OT_FUNC("%p, %p, %p, %u, %u", s, f, msg, offset, len);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN_INT(len);
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s), offset: %u, len: %u, forward: %d", flt_ot_chn_label(msg->chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s), offset, len, retval);
+
+ if (retval != len)
+ task_wakeup(s->task, TASK_WOKEN_MSG);
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+
+/***
+ * NAME
+ * flt_ot_http_end -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * msg -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+static int flt_ot_http_end(struct stream *s, struct filter *f, struct http_msg *msg)
+{
+ char *err = NULL;
+ int retval = FLT_OT_RET_OK;
+
+ FLT_OT_FUNC("%p, %p, %p", s, f, msg);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN_INT(retval);
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(msg->chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+
+/***
+ * NAME
+ * flt_ot_http_reset -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * msg -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_http_reset(struct stream *s, struct filter *f, struct http_msg *msg)
+{
+ char *err = NULL;
+
+ FLT_OT_FUNC("%p, %p, %p", s, f, msg);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(msg->chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
+
+ flt_ot_return_void(f, &err);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_http_reply -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * status -
+ * msg -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_http_reply(struct stream *s, struct filter *f, short status, const struct buffer *msg)
+{
+ char *err = NULL;
+
+ FLT_OT_FUNC("%p, %p, %hd, %p", s, f, status, msg);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG(3, "channel: -, mode: %s (%s)", flt_ot_pr_mode(s), flt_ot_stream_pos(s));
+
+ flt_ot_return_void(f, &err);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_tcp_payload -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * chn -
+ * offset -
+ * len -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, any other value otherwise.
+ */
+static int flt_ot_tcp_payload(struct stream *s, struct filter *f, struct channel *chn, uint offset, uint len)
+{
+ char *err = NULL;
+ int retval = len;
+
+ FLT_OT_FUNC("%p, %p, %p, %u, %u", s, f, chn, offset, len);
+
+ if (flt_ot_is_disabled(f FLT_OT_DBG_ARGS(, -1)))
+ FLT_OT_RETURN_INT(len);
+
+ FLT_OT_DBG(3, "channel: %s, mode: %s (%s), offset: %u, len: %u, forward: %d", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s), offset, len, retval);
+
+ if (s->flags & SF_HTX) {
+ } else {
+ }
+
+ if (retval != len)
+ task_wakeup(s->task, TASK_WOKEN_MSG);
+
+ FLT_OT_RETURN_INT(flt_ot_return_int(f, &err, retval));
+}
+
+#endif /* DEBUG_OT */
+
+
+struct flt_ops flt_ot_ops = {
+ /* Callbacks to manage the filter lifecycle. */
+ .init = flt_ot_init,
+ .deinit = flt_ot_deinit,
+ .check = flt_ot_check,
+ .init_per_thread = flt_ot_init_per_thread,
+ .deinit_per_thread = FLT_OT_DBG_IFDEF(flt_ot_deinit_per_thread, NULL),
+
+ /* Stream callbacks. */
+ .attach = flt_ot_attach,
+ .stream_start = FLT_OT_DBG_IFDEF(flt_ot_stream_start, NULL),
+ .stream_set_backend = FLT_OT_DBG_IFDEF(flt_ot_stream_set_backend, NULL),
+ .stream_stop = FLT_OT_DBG_IFDEF(flt_ot_stream_stop, NULL),
+ .detach = flt_ot_detach,
+ .check_timeouts = flt_ot_check_timeouts,
+
+ /* Channel callbacks. */
+ .channel_start_analyze = flt_ot_channel_start_analyze,
+ .channel_pre_analyze = flt_ot_channel_pre_analyze,
+ .channel_post_analyze = flt_ot_channel_post_analyze,
+ .channel_end_analyze = flt_ot_channel_end_analyze,
+
+ /* HTTP callbacks. */
+ .http_headers = FLT_OT_DBG_IFDEF(flt_ot_http_headers, NULL),
+ .http_payload = FLT_OT_DBG_IFDEF(flt_ot_http_payload, NULL),
+ .http_end = FLT_OT_DBG_IFDEF(flt_ot_http_end, NULL),
+ .http_reset = FLT_OT_DBG_IFDEF(flt_ot_http_reset, NULL),
+ .http_reply = FLT_OT_DBG_IFDEF(flt_ot_http_reply, NULL),
+
+ /* TCP callbacks. */
+ .tcp_payload = FLT_OT_DBG_IFDEF(flt_ot_tcp_payload, NULL)
+};
+
+
+REGISTER_BUILD_OPTS("Built with OpenTracing support.");
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/group.c b/addons/ot/src/group.c
new file mode 100644
index 0000000..52b872d
--- /dev/null
+++ b/addons/ot/src/group.c
@@ -0,0 +1,354 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+#define FLT_OT_GROUP_DEF(a,b,c) { a, b, c },
+const struct flt_ot_group_data flt_ot_group_data[] = { FLT_OT_GROUP_DEFINES };
+#undef FLT_OT_GROUP_DEF
+
+
+/***
+ * NAME
+ * flt_ot_group_action -
+ *
+ * ARGUMENTS
+ * rule -
+ * px -
+ * sess -
+ * s -
+ * opts -
+ *
+ * DESCRIPTION
+ * This is the action_ptr callback of a rule associated to the
+ * FLT_OT_ACTION_GROUP action.
+ *
+ * RETURN VALUE
+ * The function returns ACT_RET_CONT if processing is finished (with error or
+ * not), otherwise, it returns ACT_RET_YIELD if the action is in progress.
+ */
+static enum act_return flt_ot_group_action(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *s, int opts)
+{
+ const struct filter *filter;
+ const struct flt_conf *fconf;
+ const struct flt_ot_conf *conf;
+ const struct flt_ot_conf_group *conf_group;
+ const struct flt_ot_runtime_context *rt_ctx = NULL;
+ const struct flt_ot_conf_ph *ph_scope;
+ char *err = NULL;
+ int i, rc;
+
+ FLT_OT_FUNC("%p, %p, %p, %p, %d", rule, px, sess, s, opts);
+
+ FLT_OT_DBG(3, "from: %d, arg.act %p:{ %p %p %p %p }", rule->from, &(rule->arg.act), rule->arg.act.p[0], rule->arg.act.p[1], rule->arg.act.p[2], rule->arg.act.p[3]);
+
+ fconf = rule->arg.act.p[FLT_OT_ARG_FLT_CONF];
+ conf = rule->arg.act.p[FLT_OT_ARG_CONF];
+ conf_group = ((const struct flt_ot_conf_ph *)(rule->arg.act.p[FLT_OT_ARG_GROUP]))->ptr;
+
+ if ((fconf == NULL) || (conf == NULL) || (conf_group == NULL)) {
+ FLT_OT_LOG(LOG_ERR, FLT_OT_ACTION_GROUP ": internal error, invalid group action");
+
+ FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
+ }
+
+ if (conf->tracer->flag_disabled) {
+ FLT_OT_DBG(1, "filter '%s' disabled, group action '%s' ignored", conf->id, conf_group->id);
+
+ FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
+ }
+
+ /* Find the OpenTracing filter instance from the current stream. */
+ list_for_each_entry(filter, &(s->strm_flt.filters), list)
+ if (filter->config == fconf) {
+ rt_ctx = filter->ctx;
+
+ break;
+ }
+
+ if (rt_ctx == NULL) {
+ FLT_OT_DBG(1, "cannot find filter, probably not attached to the stream");
+
+ FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
+ }
+ else if (flt_ot_is_disabled(filter FLT_OT_DBG_ARGS(, -1))) {
+ FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
+ }
+ else {
+ FLT_OT_DBG(3, "run group '%s'", conf_group->id);
+ FLT_OT_DBG_CONF_GROUP("run group ", conf_group);
+ }
+
+ /*
+ * Check the value of rule->from; in case it is incorrect,
+ * report an error.
+ */
+ for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_group_data); i++)
+ if (flt_ot_group_data[i].act_from == rule->from)
+ break;
+
+ if (i >= FLT_OT_TABLESIZE(flt_ot_group_data)) {
+ FLT_OT_LOG(LOG_ERR, FLT_OT_ACTION_GROUP ": internal error, invalid rule->from=%d", rule->from);
+
+ FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
+ }
+
+ list_for_each_entry(ph_scope, &(conf_group->ph_scopes), list) {
+ rc = flt_ot_scope_run(s, rt_ctx->filter, &(s->res), ph_scope->ptr, NULL, SMP_OPT_DIR_RES, &err);
+ if ((rc == FLT_OT_RET_ERROR) && (opts & ACT_OPT_FINAL)) {
+ /* XXX */
+ }
+ }
+
+ FLT_OT_RETURN_EX(ACT_RET_CONT, enum act_return, "%d");
+}
+
+
+/***
+ * NAME
+ * flt_ot_group_check -
+ *
+ * ARGUMENTS
+ * rule -
+ * px -
+ * err -
+ *
+ * DESCRIPTION
+ * This is the check_ptr callback of a rule associated to the
+ * FLT_OT_ACTION_GROUP action.
+ *
+ * RETURN VALUE
+ * The function returns 1 in success case, otherwise,
+ * it returns 0 and err is filled.
+ */
+static int flt_ot_group_check(struct act_rule *rule, struct proxy *px, char **err)
+{
+ struct flt_conf *fconf_tmp, *fconf = NULL;
+ struct flt_ot_conf *conf;
+ struct flt_ot_conf_ph *ph_group;
+ const char *filter_id;
+ const char *group_id;
+ bool flag_found = 0;
+ int i;
+
+ FLT_OT_FUNC("%p, %p, %p:%p", rule, px, FLT_OT_DPTR_ARGS(err));
+
+ filter_id = rule->arg.act.p[FLT_OT_ARG_FILTER_ID];
+ group_id = rule->arg.act.p[FLT_OT_ARG_GROUP_ID];
+
+ FLT_OT_DBG(2, "checking filter_id='%s', group_id='%s'", filter_id, group_id);
+
+ /*
+ * Check the value of rule->from; in case it is incorrect,
+ * report an error.
+ */
+ for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_group_data); i++)
+ if (flt_ot_group_data[i].act_from == rule->from)
+ break;
+
+ if (i >= FLT_OT_TABLESIZE(flt_ot_group_data)) {
+ FLT_OT_ERR("internal error, unexpected rule->from=%d, please report this bug!", rule->from);
+
+ FLT_OT_RETURN_INT(0);
+ }
+
+ /*
+ * Try to find the OpenTracing filter by checking all filters
+ * for the proxy <px>.
+ */
+ list_for_each_entry(fconf_tmp, &(px->filter_configs), list) {
+ conf = fconf_tmp->conf;
+
+ if (fconf_tmp->id != ot_flt_id) {
+ /* This is not an OpenTracing filter. */
+ continue;
+ }
+ else if (strcmp(conf->id, filter_id) == 0) {
+ /* This is the good filter ID. */
+ fconf = fconf_tmp;
+
+ break;
+ }
+ }
+
+ if (fconf == NULL) {
+ FLT_OT_ERR("unable to find the OpenTracing filter '%s' used by the " FLT_OT_ACTION_GROUP " '%s'", filter_id, group_id);
+
+ FLT_OT_RETURN_INT(0);
+ }
+
+ /*
+ * Attempt to find if the group is defined in the OpenTracing filter
+ * configuration.
+ */
+ list_for_each_entry(ph_group, &(conf->tracer->ph_groups), list)
+ if (strcmp(ph_group->id, group_id) == 0) {
+ flag_found = 1;
+
+ break;
+ }
+
+ if (!flag_found) {
+ FLT_OT_ERR("unable to find group '%s' in the OpenTracing filter '%s' configuration", group_id, filter_id);
+
+ FLT_OT_RETURN_INT(0);
+ }
+
+ FLT_OT_FREE_CLEAR(rule->arg.act.p[FLT_OT_ARG_FILTER_ID]);
+ FLT_OT_FREE_CLEAR(rule->arg.act.p[FLT_OT_ARG_GROUP_ID]);
+
+ rule->arg.act.p[FLT_OT_ARG_FLT_CONF] = fconf;
+ rule->arg.act.p[FLT_OT_ARG_CONF] = conf;
+ rule->arg.act.p[FLT_OT_ARG_GROUP] = ph_group;
+
+ FLT_OT_RETURN_INT(1);
+}
+
+
+/***
+ * NAME
+ * flt_ot_group_release -
+ *
+ * ARGUMENTS
+ * rule -
+ *
+ * DESCRIPTION
+ * This is the release_ptr callback of a rule associated to the
+ * FLT_OT_ACTION_GROUP action.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_group_release(struct act_rule *rule)
+{
+ FLT_OT_FUNC("%p", rule);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_group_parse -
+ *
+ * ARGUMENTS
+ * args -
+ * cur_arg -
+ * px -
+ * rule -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ACT_RET_PRS_ERR if an error occurs, ACT_RET_PRS_OK otherwise.
+ */
+static enum act_parse_ret flt_ot_group_parse(const char **args, int *cur_arg, struct proxy *px, struct act_rule *rule, char **err)
+{
+ FLT_OT_FUNC("%p, %p, %p, %p, %p:%p", args, cur_arg, px, rule, FLT_OT_DPTR_ARGS(err));
+
+ if (!FLT_OT_ARG_ISVALID(*cur_arg) ||
+ !FLT_OT_ARG_ISVALID(*cur_arg + 1) ||
+ (FLT_OT_ARG_ISVALID(*cur_arg + 2) &&
+ (strcmp(args[*cur_arg + 2], FLT_OT_CONDITION_IF) != 0) &&
+ (strcmp(args[*cur_arg + 2], FLT_OT_CONDITION_UNLESS) != 0))) {
+ FLT_OT_ERR("expects: <filter-id> <group-id> [{ if | unless } ...]");
+
+ FLT_OT_RETURN_EX(ACT_RET_PRS_ERR, enum act_parse_ret, "%d");
+ }
+
+ /* Copy the OpenTracing filter id. */
+ rule->arg.act.p[FLT_OT_ARG_FILTER_ID] = FLT_OT_STRDUP(args[*cur_arg]);
+ if (rule->arg.act.p[FLT_OT_ARG_FILTER_ID] == NULL) {
+ FLT_OT_ERR("%s : out of memory", args[*cur_arg]);
+
+ FLT_OT_RETURN_EX(ACT_RET_PRS_ERR, enum act_parse_ret, "%d");
+ }
+
+ /* Copy the OpenTracing group id. */
+ rule->arg.act.p[FLT_OT_ARG_GROUP_ID] = FLT_OT_STRDUP(args[*cur_arg + 1]);
+ if (rule->arg.act.p[FLT_OT_ARG_GROUP_ID] == NULL) {
+ FLT_OT_ERR("%s : out of memory", args[*cur_arg + 1]);
+
+ FLT_OT_FREE_CLEAR(rule->arg.act.p[FLT_OT_ARG_FILTER_ID]);
+
+ FLT_OT_RETURN_EX(ACT_RET_PRS_ERR, enum act_parse_ret, "%d");
+ }
+
+ rule->action = ACT_CUSTOM;
+ rule->action_ptr = flt_ot_group_action;
+ rule->check_ptr = flt_ot_group_check;
+ rule->release_ptr = flt_ot_group_release;
+
+ *cur_arg += 2;
+
+ FLT_OT_RETURN_EX(ACT_RET_PRS_OK, enum act_parse_ret, "%d");
+}
+
+
+static struct action_kw_list tcp_req_action_kws = { ILH, {
+ { FLT_OT_ACTION_GROUP, flt_ot_group_parse },
+ { /* END */ },
+ }
+};
+
+INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_action_kws);
+
+static struct action_kw_list tcp_res_action_kws = { ILH, {
+ { FLT_OT_ACTION_GROUP, flt_ot_group_parse },
+ { /* END */ },
+ }
+};
+
+INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_action_kws);
+
+static struct action_kw_list http_req_action_kws = { ILH, {
+ { FLT_OT_ACTION_GROUP, flt_ot_group_parse },
+ { /* END */ },
+ }
+};
+
+INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_action_kws);
+
+static struct action_kw_list http_res_action_kws = { ILH, {
+ { FLT_OT_ACTION_GROUP, flt_ot_group_parse },
+ { /* END */ },
+ }
+};
+
+INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_action_kws);
+
+static struct action_kw_list http_after_res_actions_kws = { ILH, {
+ { FLT_OT_ACTION_GROUP, flt_ot_group_parse },
+ { /* END */ },
+ }
+};
+
+INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_actions_kws);
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/http.c b/addons/ot/src/http.c
new file mode 100644
index 0000000..517bd0d
--- /dev/null
+++ b/addons/ot/src/http.c
@@ -0,0 +1,312 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+#ifdef DEBUG_OT
+
+/***
+ * NAME
+ * flt_ot_http_headers_dump -
+ *
+ * ARGUMENTS
+ * chn -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_http_headers_dump(const struct channel *chn)
+{
+ const struct htx *htx;
+ int32_t pos;
+
+ FLT_OT_FUNC("%p", chn);
+
+ if (chn == NULL)
+ FLT_OT_RETURN();
+
+ htx = htxbuf(&(chn->buf));
+
+ if (htx_is_empty(htx))
+ FLT_OT_RETURN();
+
+ for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
+ struct htx_blk *blk = htx_get_blk(htx, pos);
+ enum htx_blk_type type = htx_get_blk_type(blk);
+
+ if (type == HTX_BLK_HDR) {
+ struct ist n = htx_get_blk_name(htx, blk);
+ struct ist v = htx_get_blk_value(htx, blk);
+
+ FLT_OT_DBG(2, "'%.*s: %.*s'", (int)n.len, n.ptr, (int)v.len, v.ptr);
+ }
+ else if (type == HTX_BLK_EOH)
+ break;
+ }
+
+ FLT_OT_RETURN();
+}
+
+#endif /* DEBUG_OT */
+
+
+/***
+ * NAME
+ * flt_ot_http_headers_get -
+ *
+ * ARGUMENTS
+ * chn -
+ * prefix -
+ * len -
+ * err -
+ *
+ * DESCRIPTION
+ * This function is very similar to function http_action_set_header(), from
+ * the HAProxy source.
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_text_map *flt_ot_http_headers_get(struct channel *chn, const char *prefix, size_t len, char **err)
+{
+ const struct htx *htx;
+ size_t prefix_len = (!FLT_OT_STR_ISVALID(prefix) || (len == 0)) ? 0 : (len + 1);
+ int32_t pos;
+ struct otc_text_map *retptr = NULL;
+
+ FLT_OT_FUNC("%p, \"%s\", %zu, %p:%p", chn, prefix, len, FLT_OT_DPTR_ARGS(err));
+
+ if (chn == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ /*
+ * The keyword 'inject' allows you to define the name of the OpenTracing
+ * context without using a prefix. In that case all HTTP headers are
+ * transferred because it is not possible to separate them from the
+ * OpenTracing context (this separation is usually done via a prefix).
+ *
+ * When using the 'extract' keyword, the context name must be specified.
+ * To allow all HTTP headers to be extracted, the first character of
+ * that name must be set to FLT_OT_PARSE_CTX_IGNORE_NAME.
+ */
+ if (FLT_OT_STR_ISVALID(prefix) && (*prefix == FLT_OT_PARSE_CTX_IGNORE_NAME))
+ prefix_len = 0;
+
+ htx = htxbuf(&(chn->buf));
+
+ for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
+ struct htx_blk *blk = htx_get_blk(htx, pos);
+ enum htx_blk_type type = htx_get_blk_type(blk);
+
+ if (type == HTX_BLK_HDR) {
+ struct ist v, n = htx_get_blk_name(htx, blk);
+
+ if ((prefix_len == 0) || ((n.len >= prefix_len) && (strncasecmp(n.ptr, prefix, len) == 0))) {
+ if (retptr == NULL) {
+ retptr = otc_text_map_new(NULL, 8);
+ if (retptr == NULL) {
+ FLT_OT_ERR("failed to create HTTP header data");
+
+ break;
+ }
+ }
+
+ v = htx_get_blk_value(htx, blk);
+
+ /*
+ * In case the data of the HTTP header is not
+ * specified, v.ptr will have some non-null
+ * value and v.len will be equal to 0. The
+ * otc_text_map_add() function will not
+ * interpret this well. In this case v.ptr
+ * is set to an empty string.
+ */
+ if (v.len == 0)
+ v = ist("");
+
+ /*
+ * Here, an HTTP header (which is actually part
+ * of the span context is added to the text_map.
+ *
+ * Before adding, the prefix is removed from the
+ * HTTP header name.
+ */
+ if (otc_text_map_add(retptr, n.ptr + prefix_len, n.len - prefix_len, v.ptr, v.len, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1) {
+ FLT_OT_ERR("failed to add HTTP header data");
+
+ otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
+
+ break;
+ }
+ }
+ }
+ else if (type == HTX_BLK_EOH)
+ break;
+ }
+
+ ot_text_map_show(retptr);
+
+ if ((retptr != NULL) && (retptr->count == 0)) {
+ FLT_OT_DBG(2, "WARNING: no HTTP headers found");
+
+ otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
+ }
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_http_header_set -
+ *
+ * ARGUMENTS
+ * chn -
+ * prefix -
+ * name -
+ * value -
+ * err -
+ *
+ * DESCRIPTION
+ * This function is very similar to function http_action_set_header(), from
+ * the HAProxy source.
+ *
+ * RETURN VALUE
+ * -
+ */
+int flt_ot_http_header_set(struct channel *chn, const char *prefix, const char *name, const char *value, char **err)
+{
+ struct http_hdr_ctx ctx = { .blk = NULL };
+ struct ist ist_name;
+ struct buffer *buffer = NULL;
+ struct htx *htx;
+ int retval = -1;
+
+ FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", %p:%p", chn, prefix, name, value, FLT_OT_DPTR_ARGS(err));
+
+ if ((chn == NULL) || (!FLT_OT_STR_ISVALID(prefix) && !FLT_OT_STR_ISVALID(name)))
+ FLT_OT_RETURN_INT(retval);
+
+ htx = htxbuf(&(chn->buf));
+
+ /*
+ * Very rare (about 1% of cases), htx is empty.
+ * In order to avoid segmentation fault, we exit this function.
+ */
+ if (htx_is_empty(htx)) {
+ FLT_OT_ERR("HTX is empty");
+
+ FLT_OT_RETURN_INT(retval);
+ }
+
+ if (!FLT_OT_STR_ISVALID(prefix)) {
+ ist_name = ist2((char *)name, strlen(name));
+ }
+ else if (!FLT_OT_STR_ISVALID(name)) {
+ ist_name = ist2((char *)prefix, strlen(prefix));
+ }
+ else {
+ buffer = flt_ot_trash_alloc(0, err);
+ if (buffer == NULL)
+ FLT_OT_RETURN_INT(retval);
+
+ (void)chunk_printf(buffer, "%s-%s", prefix, name);
+
+ ist_name = ist2(buffer->area, buffer->data);
+ }
+
+ /* Remove all occurrences of the header. */
+ while (http_find_header(htx, ist(""), &ctx, 1) == 1) {
+ struct ist n = htx_get_blk_name(htx, ctx.blk);
+#ifdef DEBUG_OT
+ struct ist v = htx_get_blk_value(htx, ctx.blk);
+#endif
+
+ /*
+ * If the <name> parameter is not set, then remove all headers
+ * that start with the contents of the <prefix> parameter.
+ */
+ if (!FLT_OT_STR_ISVALID(name))
+ n.len = ist_name.len;
+
+ if (isteqi(n, ist_name))
+ if (http_remove_header(htx, &ctx) == 1)
+ FLT_OT_DBG(3, "HTTP header '%.*s: %.*s' removed", (int)n.len, n.ptr, (int)v.len, v.ptr);
+ }
+
+ /*
+ * If the value pointer has a value of NULL, the HTTP header is not set
+ * after deletion.
+ */
+ if (value == NULL) {
+ /* Do nothing. */
+ }
+ else if (http_add_header(htx, ist_name, ist(value)) == 1) {
+ retval = 0;
+
+ FLT_OT_DBG(3, "HTTP header '%s: %s' added", ist_name.ptr, value);
+ }
+ else {
+ FLT_OT_ERR("failed to set HTTP header '%s: %s'", ist_name.ptr, value);
+ }
+
+ flt_ot_trash_free(&buffer);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_http_headers_remove -
+ *
+ * ARGUMENTS
+ * chn -
+ * prefix -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int flt_ot_http_headers_remove(struct channel *chn, const char *prefix, char **err)
+{
+ int retval;
+
+ FLT_OT_FUNC("%p, \"%s\", %p:%p", chn, prefix, FLT_OT_DPTR_ARGS(err));
+
+ retval = flt_ot_http_header_set(chn, prefix, NULL, NULL, err);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/opentracing.c b/addons/ot/src/opentracing.c
new file mode 100644
index 0000000..8ae5f02
--- /dev/null
+++ b/addons/ot/src/opentracing.c
@@ -0,0 +1,1067 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+static struct pool_head *pool_head_ot_span_context __read_mostly = NULL;
+
+#ifdef USE_POOL_OT_SPAN_CONTEXT
+REGISTER_POOL(&pool_head_ot_span_context, "ot_span_context", MAX(sizeof(struct otc_span), sizeof(struct otc_span_context)));
+#endif
+
+
+#ifdef DEBUG_OT
+
+/***
+ * NAME
+ * ot_text_map_show -
+ *
+ * ARGUMENTS
+ * text_map -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void ot_text_map_show(const struct otc_text_map *text_map)
+{
+ FLT_OT_FUNC("%p", text_map);
+
+ if (text_map == NULL)
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_TEXT_MAP(text_map);
+
+ if ((text_map->key != NULL) && (text_map->value != NULL) && (text_map->count > 0)) {
+ size_t i;
+
+ for (i = 0; i < text_map->count; i++)
+ FLT_OT_DBG(3, " \"%s\" -> \"%s\"", text_map->key[i], text_map->value[i]);
+ }
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * ot_debug -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void ot_debug(void)
+{
+ char buffer[BUFSIZ];
+
+ FLT_OT_FUNC("");
+
+ otc_statistics(buffer, sizeof(buffer));
+ FLT_OT_DBG(0, "%s", buffer);
+
+ FLT_OT_RETURN();
+}
+
+#endif /* DEBUG_OT */
+
+
+/***
+ * NAME
+ * ot_mem_malloc -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static void *ot_mem_malloc(FLT_OT_DBG_ARGS(const char *func, int line, ) size_t size)
+{
+ return flt_ot_pool_alloc(pool_head_ot_span_context, size, 1, NULL);
+}
+
+
+/***
+ * NAME
+ * ot_mem_free -
+ *
+ * ARGUMENTS
+ * func -
+ * line -
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void ot_mem_free(FLT_OT_DBG_ARGS(const char *func, int line, ) void *ptr)
+{
+ flt_ot_pool_free(pool_head_ot_span_context, &ptr);
+}
+
+
+/***
+ * NAME
+ * ot_init -
+ *
+ * ARGUMENTS
+ * tracer -
+ * plugin -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_init(struct otc_tracer **tracer, const char *plugin, char **err)
+{
+ char cwd[PATH_MAX], path[PATH_MAX], errbuf[BUFSIZ] = "";
+ int rc, retval = -1;
+
+ FLT_OT_FUNC("%p:%p, \"%s\", %p:%p", FLT_OT_DPTR_ARGS(tracer), plugin, FLT_OT_DPTR_ARGS(err));
+
+ flt_ot_pools_info();
+#ifdef USE_POOL_OT_SPAN_CONTEXT
+ FLT_OT_DBG(2, "sizeof_pool(ot_span_context) = %u", pool_head_ot_span_context->size);
+#endif
+
+ if (getcwd(cwd, sizeof(cwd)) == NULL) {
+ FLT_OT_ERR("failed to get current working directory");
+
+ FLT_OT_RETURN_INT(retval);
+ }
+ rc = snprintf(path, sizeof(path), "%s/%s", cwd, plugin);
+ if ((rc == -1) || (rc >= sizeof(path))) {
+ FLT_OT_ERR("failed to construct the OpenTracing plugin path");
+
+ FLT_OT_RETURN_INT(retval);
+ }
+
+ *tracer = otc_tracer_load(path, errbuf, sizeof(errbuf));
+ if (*tracer == NULL) {
+ FLT_OT_ERR("%s", (*errbuf == '\0') ? "failed to initialize tracing library" : errbuf);
+ } else {
+ otc_ext_init(ot_mem_malloc, ot_mem_free);
+
+ retval = 0;
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * ot_start -
+ *
+ * ARGUMENTS
+ * tracer -
+ * cfgbuf -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+int ot_start(struct otc_tracer *tracer, const char *cfgbuf, char **err)
+{
+ char errbuf[BUFSIZ] = "";
+ int retval = -1;
+
+ FLT_OT_FUNC("%p, %p, %p:%p", tracer, cfgbuf, FLT_OT_DPTR_ARGS(err));
+
+ if (cfgbuf == NULL)
+ FLT_OT_RETURN_INT(retval);
+
+ retval = otc_tracer_start(NULL, cfgbuf, errbuf, sizeof(errbuf));
+ if (retval == -1)
+ FLT_OT_ERR("%s", (*errbuf == '\0') ? "failed to start tracer" : errbuf);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * ot_close -
+ *
+ * ARGUMENTS
+ * tracer -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void ot_close(struct otc_tracer **tracer)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(tracer));
+
+ if ((tracer == NULL) || (*tracer == NULL))
+ FLT_OT_RETURN();
+
+ (*tracer)->close(*tracer);
+
+ *tracer = NULL;
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * ot_span_init -
+ *
+ * ARGUMENTS
+ * tracer -
+ * operation_name -
+ * ts_steady -
+ * ts_system -
+ * ref_type -
+ * ref_ctx_idx -
+ * ref_span -
+ * tags -
+ * num_tags -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span *ot_span_init(struct otc_tracer *tracer, const char *operation_name, const struct timespec *ts_steady, const struct timespec *ts_system, int ref_type, int ref_ctx_idx, const struct otc_span *ref_span, const struct otc_tag *tags, int num_tags, char **err)
+{
+ struct otc_start_span_options options;
+ struct otc_span_context context = { .idx = ref_ctx_idx, .span = ref_span };
+ struct otc_span_reference references = { ref_type, &context };
+ struct otc_span *retptr = NULL;
+
+ FLT_OT_FUNC("%p, \"%s\", %p, %p, %d, %d, %p, %p, %d, %p:%p", tracer, operation_name, ts_steady, ts_system, ref_type, ref_ctx_idx, ref_span, tags, num_tags, FLT_OT_DPTR_ARGS(err));
+
+ if (operation_name == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+ else if (tracer == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ (void)memset(&options, 0, sizeof(options));
+
+ if (ts_steady != NULL)
+ (void)memcpy(&(options.start_time_steady.value), ts_steady, sizeof(options.start_time_steady.value));
+
+ if (ts_system != NULL)
+ (void)memcpy(&(options.start_time_system.value), ts_system, sizeof(options.start_time_system.value));
+
+ if (FLT_OT_IN_RANGE(ref_type, otc_span_reference_child_of, otc_span_reference_follows_from)) {
+ options.references = &references;
+ options.num_references = 1;
+ }
+
+ options.tags = tags;
+ options.num_tags = num_tags;
+
+ retptr = tracer->start_span_with_options(tracer, operation_name, &options);
+ if (retptr == NULL)
+ FLT_OT_ERR("failed to init new span");
+ else
+ FLT_OT_DBG(2, "span %p:%zd initialized", retptr, retptr->idx);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * ot_span_init_va -
+ *
+ * ARGUMENTS
+ * tracer -
+ * operation_name -
+ * ts_steady -
+ * ts_system -
+ * ref_type -
+ * ref_ctx_idx -
+ * ref_span -
+ * err -
+ * tag_key -
+ * tag_value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span *ot_span_init_va(struct otc_tracer *tracer, const char *operation_name, const struct timespec *ts_steady, const struct timespec *ts_system, int ref_type, int ref_ctx_idx, const struct otc_span *ref_span, char **err, const char *tag_key, const char *tag_value, ...)
+{
+ struct otc_tag tags[FLT_OT_MAXTAGS];
+ int num_tags = 0;
+ struct otc_span *retptr;
+
+ FLT_OT_FUNC("%p, \"%s\", %p, %p, %d, %d, %p, %p:%p, \"%s\", \"%s\", ...", tracer, operation_name, ts_steady, ts_system, ref_type, ref_ctx_idx, ref_span, FLT_OT_DPTR_ARGS(err), tag_key, tag_value);
+
+ if (tag_key != NULL) {
+ va_list ap;
+
+ va_start(ap, tag_value);
+ for (num_tags = 0; (num_tags < FLT_OT_TABLESIZE(tags)) && (tag_key != NULL) && (tag_value != NULL); num_tags++) {
+ tags[num_tags].key = (char *)tag_key;
+ FLT_OT_VSET(&(tags[num_tags].value), string, tag_value);
+
+ tag_key = va_arg(ap, typeof(tag_key));
+ if (tag_key != NULL)
+ tag_value = va_arg(ap, typeof(tag_value));
+ }
+ va_end(ap);
+ }
+
+ retptr = ot_span_init(tracer, operation_name, ts_steady, ts_system, ref_type, ref_ctx_idx, ref_span, tags, num_tags, err);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * ot_span_tag -
+ *
+ * ARGUMENTS
+ * span -
+ * tags -
+ * num_tags -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_tag(struct otc_span *span, const struct otc_tag *tags, int num_tags)
+{
+ int retval = -1;
+
+ FLT_OT_FUNC("%p, %p, %d", span, tags, num_tags);
+
+ if ((span == NULL) || (tags == NULL))
+ FLT_OT_RETURN_INT(retval);
+
+ for (retval = 0; retval < num_tags; retval++)
+ span->set_tag(span, tags[retval].key, &(tags[retval].value));
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * ot_span_tag_va -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * type -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_tag_va(struct otc_span *span, const char *key, int type, ...)
+{
+ va_list ap;
+ struct otc_value ot_value;
+ int retval = -1;
+
+ FLT_OT_FUNC("%p, \"%s\", %d, ...", span, key, type);
+
+ if ((span == NULL) || (key == NULL))
+ FLT_OT_RETURN_INT(retval);
+
+ va_start(ap, type);
+ for (retval = 0; (key != NULL) && FLT_OT_IN_RANGE(type, otc_value_bool, otc_value_null); retval++) {
+ ot_value.type = type;
+ if (type == otc_value_bool)
+ ot_value.value.bool_value = va_arg(ap, typeof(ot_value.value.bool_value));
+ else if (type == otc_value_double)
+ ot_value.value.double_value = va_arg(ap, typeof(ot_value.value.double_value));
+ else if (type == otc_value_int64)
+ ot_value.value.int64_value = va_arg(ap, typeof(ot_value.value.int64_value));
+ else if (type == otc_value_uint64)
+ ot_value.value.uint64_value = va_arg(ap, typeof(ot_value.value.uint64_value));
+ else if (type == otc_value_string)
+ ot_value.value.string_value = va_arg(ap, typeof(ot_value.value.string_value));
+ else if (type == otc_value_null)
+ ot_value.value.string_value = va_arg(ap, typeof(ot_value.value.string_value));
+ span->set_tag(span, key, &ot_value);
+
+ key = va_arg(ap, typeof(key));
+ if (key != NULL)
+ type = va_arg(ap, typeof(type));
+ }
+ va_end(ap);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * ot_span_log -
+ *
+ * ARGUMENTS
+ * span -
+ * log_fields -
+ * num_fields -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_log(struct otc_span *span, const struct otc_log_field *log_fields, int num_fields)
+{
+ int retval = -1;
+
+ FLT_OT_FUNC("%p, %p, %d", span, log_fields, num_fields);
+
+ if ((span == NULL) || (log_fields == NULL))
+ FLT_OT_RETURN_INT(retval);
+
+ retval = MIN(OTC_MAXLOGFIELDS, num_fields);
+
+ span->log_fields(span, log_fields, retval);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * ot_span_log_va -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_log_va(struct otc_span *span, const char *key, const char *value, ...)
+{
+ va_list ap;
+ struct otc_log_field log_field[OTC_MAXLOGFIELDS];
+ int retval = -1;
+
+ FLT_OT_FUNC("%p, \"%s\", \"%s\", ...", span, key, value);
+
+ if ((span == NULL) || (key == NULL) || (value == NULL))
+ FLT_OT_RETURN_INT(retval);
+
+ va_start(ap, value);
+ for (retval = 0; (retval < FLT_OT_TABLESIZE(log_field)) && (key != NULL); retval++) {
+ log_field[retval].key = key;
+ log_field[retval].value.type = otc_value_string;
+ log_field[retval].value.value.string_value = value;
+
+ key = va_arg(ap, typeof(key));
+ if (key != NULL)
+ value = va_arg(ap, typeof(value));
+ }
+ va_end(ap);
+
+ span->log_fields(span, log_field, retval);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * ot_span_log_fmt -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * format -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_log_fmt(struct otc_span *span, const char *key, const char *format, ...)
+{
+ va_list ap;
+ char value[BUFSIZ];
+ int n;
+
+ FLT_OT_FUNC("%p, \"%s\", \"%s\", ...", span, key, format);
+
+ if ((span == NULL) || (key == NULL) || (format == NULL))
+ FLT_OT_RETURN_INT(-1);
+
+ va_start(ap, format);
+ n = vsnprintf(value, sizeof(value), format, ap);
+ if (!FLT_OT_IN_RANGE(n, 0, sizeof(value) - 1)) {
+ FLT_OT_DBG(2, "WARNING: log buffer too small (%d > %zu)", n, sizeof(value));
+
+ FLT_OT_STR_ELLIPSIS(value, sizeof(value));
+ }
+ va_end(ap);
+
+ FLT_OT_RETURN_INT(ot_span_log_va(span, key, value, NULL));
+}
+
+
+/***
+ * NAME
+ * ot_span_set_baggage -
+ *
+ * ARGUMENTS
+ * span -
+ * baggage -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_set_baggage(struct otc_span *span, const struct otc_text_map *baggage)
+{
+ size_t i;
+ int retval = -1;
+
+ FLT_OT_FUNC("%p, %p", span, baggage);
+
+ if ((span == NULL) || (baggage == NULL))
+ FLT_OT_RETURN_INT(retval);
+
+ if ((baggage->key == NULL) || (baggage->value == NULL))
+ FLT_OT_RETURN_INT(retval);
+
+ for (retval = i = 0; i < baggage->count; i++) {
+ FLT_OT_DBG(3, "set baggage: \"%s\" -> \"%s\"", baggage->key[i], baggage->value[i]);
+
+ if ((baggage->key[i] != NULL) && (baggage->value[i] != NULL)) {
+ span->set_baggage_item(span, baggage->key[i], baggage->value[i]);
+
+ retval++;
+ }
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * ot_span_set_baggage_va -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ * value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int ot_span_set_baggage_va(struct otc_span *span, const char *key, const char *value, ...)
+{
+ va_list ap;
+ int retval = -1;
+
+ FLT_OT_FUNC("%p, \"%s\", \"%s\", ...", span, key, value);
+
+ if ((span == NULL) || (key == NULL) || (value == NULL))
+ FLT_OT_RETURN_INT(retval);
+
+ va_start(ap, value);
+ for (retval = 0; (key != NULL); retval++) {
+ FLT_OT_DBG(3, "set baggage: \"%s\" -> \"%s\"", key, value);
+
+ span->set_baggage_item(span, key, value);
+
+ key = va_arg(ap, typeof(key));
+ if (key != NULL)
+ value = va_arg(ap, typeof(value));
+ }
+ va_end(ap);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * ot_span_baggage_va -
+ *
+ * ARGUMENTS
+ * span -
+ * key -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_text_map *ot_span_baggage_va(const struct otc_span *span, const char *key, ...)
+{
+ va_list ap;
+ struct otc_text_map *retptr = NULL;
+ int i, n;
+
+ FLT_OT_FUNC("%p, \"%s\", ...", span, key);
+
+ if ((span == NULL) || (key == NULL))
+ FLT_OT_RETURN_PTR(retptr);
+
+ va_start(ap, key);
+ for (n = 1; va_arg(ap, typeof(key)) != NULL; n++);
+ va_end(ap);
+
+ retptr = otc_text_map_new(NULL, n);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ va_start(ap, key);
+ for (i = 0; (i < n) && (key != NULL); i++) {
+ char *value = (char *)span->baggage_item(span, key);
+
+ if (value != NULL) {
+ (void)otc_text_map_add(retptr, key, 0, value, 0, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE);
+
+ FLT_OT_DBG(3, "get baggage[%d]: \"%s\" -> \"%s\"", i, retptr->key[i], retptr->value[i]);
+ } else {
+ FLT_OT_DBG(3, "get baggage[%d]: \"%s\" -> invalid key", i, key);
+ }
+
+ key = va_arg(ap, typeof(key));
+ }
+ va_end(ap);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * ot_inject_text_map -
+ *
+ * ARGUMENTS
+ * tracer -
+ * span -
+ * carrier -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_inject_text_map(struct otc_tracer *tracer, const struct otc_span *span, struct otc_text_map_writer *carrier)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ FLT_OT_FUNC("%p, %p, %p", tracer, span, carrier);
+
+ if ((span == NULL) || (carrier == NULL))
+ FLT_OT_RETURN_PTR(retptr);
+ else if (tracer == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ retptr = span->span_context((struct otc_span *)span);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ (void)memset(carrier, 0, sizeof(*carrier));
+
+ rc = tracer->inject_text_map(tracer, carrier, retptr);
+ if (rc != otc_propagation_error_code_success) {
+ FLT_OT_FREE_CLEAR(retptr);
+ } else {
+#ifdef DEBUG_OT
+ FLT_OT_DBG_TEXT_CARRIER(carrier, set);
+ ot_text_map_show(&(carrier->text_map));
+ FLT_OT_DBG_SPAN_CONTEXT(retptr);
+#endif
+ }
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * ot_inject_http_headers -
+ *
+ * ARGUMENTS
+ * tracer -
+ * span -
+ * carrier -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_inject_http_headers(struct otc_tracer *tracer, const struct otc_span *span, struct otc_http_headers_writer *carrier, char **err)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ FLT_OT_FUNC("%p, %p, %p, %p:%p", tracer, span, carrier, FLT_OT_DPTR_ARGS(err));
+
+ if ((span == NULL) || (carrier == NULL))
+ FLT_OT_RETURN_PTR(retptr);
+ else if (tracer == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ retptr = span->span_context((struct otc_span *)span);
+ if (retptr == NULL) {
+ FLT_OT_ERR("failed to create span context");
+
+ FLT_OT_RETURN_PTR(retptr);
+ }
+
+ (void)memset(carrier, 0, sizeof(*carrier));
+
+ rc = tracer->inject_http_headers(tracer, carrier, retptr);
+ if (rc != otc_propagation_error_code_success) {
+ FLT_OT_ERR("failed to inject HTTP headers data");
+
+ FLT_OT_FREE_CLEAR(retptr);
+ } else {
+#ifdef DEBUG_OT
+ FLT_OT_DBG_TEXT_CARRIER(carrier, set);
+ ot_text_map_show(&(carrier->text_map));
+ FLT_OT_DBG_SPAN_CONTEXT(retptr);
+#endif
+ }
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * ot_inject_binary -
+ *
+ * ARGUMENTS
+ * tracer -
+ * span -
+ * carrier -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_inject_binary(struct otc_tracer *tracer, const struct otc_span *span, struct otc_custom_carrier_writer *carrier)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ FLT_OT_FUNC("%p, %p, %p", tracer, span, carrier);
+
+ if ((span == NULL) || (carrier == NULL))
+ FLT_OT_RETURN_PTR(retptr);
+ else if (tracer == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ retptr = span->span_context((struct otc_span *)span);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ (void)memset(carrier, 0, sizeof(*carrier));
+
+ rc = tracer->inject_binary(tracer, carrier, retptr);
+ if (rc != otc_propagation_error_code_success) {
+ FLT_OT_FREE_CLEAR(retptr);
+ } else {
+#ifdef DEBUG_OT
+ struct otc_jaeger_trace_context *ctx = carrier->binary_data.data;
+
+ FLT_OT_DBG_CUSTOM_CARRIER(carrier, inject);
+ FLT_OT_DBG(3, "trace context: %016" PRIx64 "%016" PRIx64 ":%016" PRIx64 ":%016" PRIx64 ":%02hhx <%s> <%s>",
+ ctx->trace_id[0], ctx->trace_id[1], ctx->span_id, ctx->parent_span_id, ctx->flags,
+ flt_ot_str_hex(ctx->baggage, carrier->binary_data.size - sizeof(*ctx)),
+ flt_ot_str_ctrl(ctx->baggage, carrier->binary_data.size - sizeof(*ctx)));
+ FLT_OT_DBG_SPAN_CONTEXT(retptr);
+#endif
+ }
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * ot_extract_text_map -
+ *
+ * ARGUMENTS
+ * tracer -
+ * carrier -
+ * text_map -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_extract_text_map(struct otc_tracer *tracer, struct otc_text_map_reader *carrier, const struct otc_text_map *text_map)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ FLT_OT_FUNC("%p, %p, %p", tracer, carrier, text_map);
+
+ if (carrier == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+ else if (tracer == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ if (text_map != NULL) {
+ (void)memset(carrier, 0, sizeof(*carrier));
+ (void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map));
+
+ FLT_OT_DBG_TEXT_CARRIER(carrier, foreach_key);
+ }
+
+ rc = tracer->extract_text_map(tracer, carrier, &retptr);
+ if (rc != otc_propagation_error_code_success)
+ FLT_OT_FREE_CLEAR(retptr);
+ else if (retptr != NULL)
+ FLT_OT_DBG_SPAN_CONTEXT(retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * ot_extract_http_headers -
+ *
+ * ARGUMENTS
+ * tracer -
+ * carrier -
+ * text_map -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_extract_http_headers(struct otc_tracer *tracer, struct otc_http_headers_reader *carrier, const struct otc_text_map *text_map, char **err)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ FLT_OT_FUNC("%p, %p, %p, %p:%p", tracer, carrier, text_map, FLT_OT_DPTR_ARGS(err));
+
+ if (carrier == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+ else if (tracer == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ if (text_map != NULL) {
+ (void)memset(carrier, 0, sizeof(*carrier));
+ (void)memcpy(&(carrier->text_map), text_map, sizeof(carrier->text_map));
+
+ FLT_OT_DBG_TEXT_CARRIER(carrier, foreach_key);
+ }
+
+ rc = tracer->extract_http_headers(tracer, carrier, &retptr);
+ if (rc != otc_propagation_error_code_success) {
+ FLT_OT_ERR("failed to extract HTTP headers data");
+
+ FLT_OT_FREE_CLEAR(retptr);
+ }
+ else if (retptr != NULL)
+ FLT_OT_DBG_SPAN_CONTEXT(retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * ot_extract_binary -
+ *
+ * ARGUMENTS
+ * tracer -
+ * carrier -
+ * binary_data -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_span_context *ot_extract_binary(struct otc_tracer *tracer, struct otc_custom_carrier_reader *carrier, const struct otc_binary_data *binary_data)
+{
+ struct otc_span_context *retptr = NULL;
+ int rc;
+
+ FLT_OT_FUNC("%p, %p, %p", tracer, carrier, binary_data);
+
+ if (carrier == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+ else if (tracer == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ if ((FLT_OT_DEREF(binary_data, data, NULL) != NULL) && (binary_data->size > 0)) {
+ (void)memset(carrier, 0, sizeof(*carrier));
+ (void)memcpy(&(carrier->binary_data), binary_data, sizeof(carrier->binary_data));
+
+ FLT_OT_DBG_CUSTOM_CARRIER(carrier, extract);
+ }
+
+ rc = tracer->extract_binary(tracer, carrier, &retptr);
+ if (rc != otc_propagation_error_code_success)
+ FLT_OT_FREE_CLEAR(retptr);
+ else if (retptr != NULL)
+ FLT_OT_DBG_SPAN_CONTEXT(retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * ot_span_finish -
+ *
+ * ARGUMENTS
+ * span -
+ * ts_finish -
+ * log_ts -
+ * log_key -
+ * log_value -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void ot_span_finish(struct otc_span **span, const struct timespec *ts_finish, const struct timespec *log_ts, const char *log_key, const char *log_value, ...)
+{
+ struct otc_finish_span_options options;
+ struct otc_log_field log_field[OTC_MAXLOGFIELDS];
+ struct otc_log_record log_records = { .fields = log_field, .num_fields = 0 };
+#ifdef DEBUG_OT
+ typeof((*span)->idx) idx = FLT_OT_DDEREF(span, idx, 0);
+#endif
+
+ FLT_OT_FUNC("%p:%p, %p, %p, \"%s\", \"%s\", ...", FLT_OT_DPTR_ARGS(span), ts_finish, log_ts, log_key, log_value);
+
+ if ((span == NULL) || (*span == NULL))
+ FLT_OT_RETURN();
+
+ (void)memset(&options, 0, sizeof(options));
+
+ if (ts_finish != NULL)
+ (void)memcpy(&(options.finish_time.value), ts_finish, sizeof(options.finish_time.value));
+
+ if (log_key != NULL) {
+ va_list ap;
+ int i;
+
+ if (log_ts != NULL)
+ (void)memcpy(&(log_records.timestamp.value), log_ts, sizeof(log_records.timestamp.value));
+
+ va_start(ap, log_value);
+ for (i = 0; (i < FLT_OT_TABLESIZE(log_field)) && (log_key != NULL); i++) {
+ log_field[i].key = log_key;
+ log_field[i].value.type = otc_value_string;
+ log_field[i].value.value.string_value = log_value;
+
+ log_key = va_arg(ap, typeof(log_key));
+ if (log_key != NULL)
+ log_value = va_arg(ap, typeof(log_value));
+ }
+ va_end(ap);
+
+ log_records.num_fields = i;
+ options.log_records = &log_records;
+ options.num_log_records = 1;
+ }
+
+ /*
+ * Caution: memory allocated for the span is released
+ * in the function finish_with_options().
+ */
+ (*span)->finish_with_options(*span, &options);
+
+ FLT_OT_DBG(2, "span %p:%zu finished", *span, idx);
+
+ *span = NULL;
+
+ FLT_OT_RETURN();
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/parser.c b/addons/ot/src/parser.c
new file mode 100644
index 0000000..f4f3e04
--- /dev/null
+++ b/addons/ot/src/parser.c
@@ -0,0 +1,1225 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+#ifdef DEBUG_OT
+struct flt_ot_debug flt_ot_debug;
+THREAD_LOCAL int dbg_indent_level = 0;
+#endif
+
+#ifdef OTC_DBG_MEM
+static struct otc_dbg_mem_data dbg_mem_data[1000000];
+static struct otc_dbg_mem dbg_mem;
+#endif
+
+static struct flt_ot_conf *flt_ot_current_config = NULL;
+static struct flt_ot_conf_tracer *flt_ot_current_tracer = NULL;
+static struct flt_ot_conf_group *flt_ot_current_group = NULL;
+static struct flt_ot_conf_scope *flt_ot_current_scope = NULL;
+static struct flt_ot_conf_span *flt_ot_current_span = NULL;
+
+
+/***
+ * NAME
+ * flt_ot_parse_strdup -
+ *
+ * ARGUMENTS
+ * ptr -
+ * str -
+ * err -
+ * err_msg -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_strdup(char **ptr, const char *str, char **err, const char *err_msg)
+{
+ int retval = ERR_NONE;
+
+ FLT_OT_FUNC("%p:%p, %p, %p:%p, \"%s\"", FLT_OT_DPTR_ARGS(ptr), str, FLT_OT_DPTR_ARGS(err), err_msg);
+
+ *ptr = FLT_OT_STRDUP(str);
+ if (*ptr == NULL) {
+ FLT_OT_PARSE_ERR(err, "'%s' : out of memory", err_msg);
+
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_keyword -
+ *
+ * ARGUMENTS
+ * ptr -
+ * args -
+ * cur_arg -
+ * pos -
+ * err -
+ * err_msg -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_keyword(char **ptr, char **args, int cur_arg, int pos, char **err, const char *err_msg)
+{
+ int retval = ERR_NONE;
+
+ FLT_OT_FUNC("%p:%p, %p, %d, %d, %p:%p, \"%s\"", FLT_OT_DPTR_ARGS(ptr), args, cur_arg, pos, FLT_OT_DPTR_ARGS(err), err_msg);
+
+ if (*ptr != NULL) {
+ if (cur_arg == pos)
+ FLT_OT_PARSE_ERR(err, FLT_OT_FMT_TYPE "%s already set", err_msg);
+ else
+ FLT_OT_PARSE_ERR(err, "'%s' : %s already set", args[cur_arg], err_msg);
+ }
+ else if (!FLT_OT_ARG_ISVALID(pos + 1)) {
+ if (cur_arg == pos)
+ FLT_OT_PARSE_ERR(err, FLT_OT_FMT_TYPE "no %s set", err_msg);
+ else
+ FLT_OT_PARSE_ERR(err, "'%s' : no %s set", args[cur_arg], err_msg);
+ }
+ else {
+ retval = flt_ot_parse_strdup(ptr, args[pos + 1], err, args[cur_arg]);
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_invalid_char -
+ *
+ * ARGUMENTS
+ * name -
+ * type -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static const char *flt_ot_parse_invalid_char(const char *name, int type)
+{
+ const char *retptr = NULL;
+
+ FLT_OT_FUNC("\"%s\", %d", name, type);
+
+ if (!FLT_OT_STR_ISVALID(name))
+ FLT_OT_RETURN_EX(retptr, const char *, "%p");
+
+ if (type == FLT_OT_PARSE_INVALID_CHAR) {
+ retptr = invalid_char(name);
+ }
+ else if (type == FLT_OT_PARSE_INVALID_DOM) {
+ retptr = invalid_domainchar(name);
+ }
+ else if (type == FLT_OT_PARSE_INVALID_CTX) {
+ retptr = invalid_prefix_char(name);
+ }
+ else if (type == FLT_OT_PARSE_INVALID_VAR) {
+ retptr = name;
+
+ /*
+ * Allowed characters are letters, numbers and '_', the first
+ * character in the string must not be a number.
+ */
+ if (!isdigit(*retptr))
+ for (++retptr; (*retptr == '_') || isalnum(*retptr); retptr++);
+
+ if (*retptr == '\0')
+ retptr = NULL;
+ }
+
+ FLT_OT_RETURN_EX(retptr, const char *, "%p");
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg_check -
+ *
+ * ARGUMENTS
+ * file -
+ * linenum -
+ * args -
+ * id -
+ * parse_data -
+ * parse_data_size -
+ * pdata -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg_check(const char *file, int linenum, char **args, const void *id, const struct flt_ot_parse_data *parse_data, size_t parse_data_size, const struct flt_ot_parse_data **pdata, char **err)
+{
+ int i, argc, retval = ERR_NONE;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p, %p, %zu, %p:%p, %p:%p", file, linenum, args, id, parse_data, parse_data_size, FLT_OT_DPTR_ARGS(pdata), FLT_OT_DPTR_ARGS(err));
+
+ FLT_OT_ARGS_DUMP();
+
+ *pdata = NULL;
+
+ /* First check here if args[0] is the correct keyword. */
+ for (i = 0; (*pdata == NULL) && (i < parse_data_size); i++)
+ if (strcmp(parse_data[i].name, args[0]) == 0)
+ *pdata = parse_data + i;
+
+ if (*pdata == NULL)
+ FLT_OT_PARSE_ERR(err, "'%s' : unknown keyword", args[0]);
+ else
+ argc = flt_ot_args_count(args);
+
+ if ((retval & ERR_CODE) || (id == NULL))
+ /* Do nothing. */;
+ else if ((id != flt_ot_current_tracer) && (flt_ot_current_config->tracer == NULL))
+ FLT_OT_PARSE_ERR(err, "tracer not defined");
+
+ /*
+ * Checking that fewer arguments are specified in the configuration
+ * line than is required.
+ */
+ if (!(retval & ERR_CODE))
+ if (argc < (*pdata)->args_min)
+ FLT_OT_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[0], (*pdata)->name, (*pdata)->usage);
+
+ /*
+ * Checking that more arguments are specified in the configuration
+ * line than the maximum allowed.
+ */
+ if (!(retval & ERR_CODE) && ((*pdata)->args_max > 0))
+ if (argc > (*pdata)->args_max)
+ FLT_OT_PARSE_ERR(err, "'%s' : too many arguments (use '%s%s')", args[0], (*pdata)->name, (*pdata)->usage);
+
+ /* Checking that the first argument has only allowed characters. */
+ if (!(retval & ERR_CODE) && ((*pdata)->check_name != FLT_OT_PARSE_INVALID_NONE)) {
+ const char *ic;
+
+ ic = flt_ot_parse_invalid_char(args[1], (*pdata)->check_name);
+ if (ic != NULL)
+ FLT_OT_PARSE_ERR(err, "%s '%s' : invalid character '%c'", args[0], args[1], *ic);
+ }
+
+ /* Checking that the data group name is defined. */
+ if (!(retval & ERR_CODE) && (*pdata)->flag_check_id && (id == NULL))
+ FLT_OT_PARSE_ERR(err, "'%s' : %s ID not set (use '%s%s')", args[0], parse_data[1].name, parse_data[1].name, parse_data[1].usage);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg_sample_expr -
+ *
+ * ARGUMENTS
+ * file -
+ * linenum -
+ * args -
+ * idx -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg_sample_expr(const char *file, int linenum, char **args, int *idx, struct list *head, char **err)
+{
+ struct flt_ot_conf_sample_expr *expr;
+ int retval = ERR_NONE;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p, %p, %p:%p", file, linenum, args, idx, head, FLT_OT_DPTR_ARGS(err));
+
+ expr = flt_ot_conf_sample_expr_init(args[*idx], linenum, head, err);
+ if (expr != NULL) {
+ expr->expr = sample_parse_expr(args, idx, file, linenum, err, &(flt_ot_current_config->proxy->conf.args), NULL);
+ if (expr->expr != NULL)
+ FLT_OT_DBG(3, "sample expression '%s' added", expr->value);
+ else
+ retval |= ERR_ABORT | ERR_ALERT;
+ } else {
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+
+ if (retval & ERR_CODE)
+ flt_ot_conf_sample_expr_free(&expr);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg_sample -
+ *
+ * ARGUMENTS
+ * file -
+ * linenum -
+ * args -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg_sample(const char *file, int linenum, char **args, struct list *head, char **err)
+{
+ struct flt_ot_conf_sample *sample;
+ int idx = 2, retval = ERR_NONE;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p, %p:%p", file, linenum, args, head, FLT_OT_DPTR_ARGS(err));
+
+ sample = flt_ot_conf_sample_init(args, linenum, head, err);
+ if (sample == NULL)
+ FLT_OT_PARSE_ERR(err, "'%s' : out of memory", args[0]);
+
+ if (!(retval & ERR_CODE)) {
+ flt_ot_current_config->proxy->conf.args.ctx = ARGC_OT;
+ flt_ot_current_config->proxy->conf.args.file = file;
+ flt_ot_current_config->proxy->conf.args.line = linenum;
+
+ while (!(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(idx))
+ retval = flt_ot_parse_cfg_sample_expr(file, linenum, args, &idx, &(sample->exprs), err);
+
+ flt_ot_current_config->proxy->conf.args.file = NULL;
+ flt_ot_current_config->proxy->conf.args.line = 0;
+ }
+
+ if (retval & ERR_CODE)
+ flt_ot_conf_sample_free(&sample);
+ else
+ FLT_OT_DBG(3, "sample '%s' -> '%s' added", sample->key, sample->value);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg_str -
+ *
+ * ARGUMENTS
+ * file -
+ * linenum -
+ * args -
+ * head -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg_str(const char *file, int linenum, char **args, struct list *head, char **err)
+{
+ struct flt_ot_conf_str *str = NULL;
+ int i, retval = ERR_NONE;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p, %p:%p", file, linenum, args, head, FLT_OT_DPTR_ARGS(err));
+
+ for (i = 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(i); i++)
+ if (flt_ot_conf_str_init(args[i], linenum, head, err) == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+
+ if (retval & ERR_CODE)
+ flt_ot_conf_str_free(&str);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg_file -
+ *
+ * ARGUMENTS
+ * ptr -
+ * file -
+ * linenum -
+ * args -
+ * err -
+ * err_msg -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg_file(char **ptr, const char *file, int linenum, char **args, char **err, const char *err_msg)
+{
+ int retval = ERR_NONE;
+
+ FLT_OT_FUNC("%p:%p, \"%s\", %d, %p, %p:%p, \"%s\"", FLT_OT_DPTR_ARGS(ptr), file, linenum, args, FLT_OT_DPTR_ARGS(err), err_msg);
+
+ if (!FLT_OT_ARG_ISVALID(1))
+ FLT_OT_PARSE_ERR(err, "'%s' : no %s specified", flt_ot_current_tracer->id, err_msg);
+ else if (alertif_too_many_args(1, file, linenum, args, &retval))
+ retval |= ERR_ABORT | ERR_ALERT;
+ else if (access(args[1], R_OK) == -1)
+ FLT_OT_PARSE_ERR(err, "'%s' : %s", args[1], strerror(errno));
+ else
+ retval = flt_ot_parse_keyword(ptr, args, 0, 0, err, err_msg);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_check_scope -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns TRUE in case the configuration is not in the currently defined
+ * scope, FALSE otherwise.
+ */
+static bool flt_ot_parse_check_scope(void)
+{
+ bool retval = 0;
+
+ if ((cfg_scope != NULL) && (flt_ot_current_config->id != NULL) && (strcmp(flt_ot_current_config->id, cfg_scope) != 0)) {
+ FLT_OT_DBG(1, "cfg_scope: '%s', id: '%s'", cfg_scope, flt_ot_current_config->id);
+
+ retval = 1;
+ }
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg_tracer -
+ *
+ * ARGUMENTS
+ * file -
+ * linenum -
+ * args -
+ * kw_mod -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg_tracer(const char *file, int linenum, char **args, int kw_mod)
+{
+#define FLT_OT_PARSE_TRACER_DEF(a,b,c,d,e,f,g) { FLT_OT_PARSE_TRACER_##a, b, FLT_OT_PARSE_INVALID_##c, d, e, f, g },
+ static const struct flt_ot_parse_data parse_data[] = { FLT_OT_PARSE_TRACER_DEFINES };
+#undef FLT_OT_PARSE_TRACER_DEF
+ const struct flt_ot_parse_data *pdata = NULL;
+ char *err = NULL, *err_log = NULL;
+ int i, retval = ERR_NONE;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, 0x%08x", file, linenum, args, kw_mod);
+
+ if (flt_ot_parse_check_scope())
+ FLT_OT_RETURN_INT(retval);
+
+ retval = flt_ot_parse_cfg_check(file, linenum, args, flt_ot_current_tracer, parse_data, FLT_OT_TABLESIZE(parse_data), &pdata, &err);
+ if (retval & ERR_CODE) {
+ FLT_OT_PARSE_IFERR_ALERT();
+
+ FLT_OT_RETURN_INT(retval);
+ }
+
+ if (pdata->keyword == FLT_OT_PARSE_TRACER_ID) {
+ if (flt_ot_current_config->tracer != NULL) {
+ FLT_OT_PARSE_ERR(&err, "'%s' : tracer can be defined only once", args[1]);
+ } else {
+ flt_ot_current_tracer = flt_ot_conf_tracer_init(args[1], linenum, &err);
+ if (flt_ot_current_tracer == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_TRACER_LOG) {
+ if (parse_logger(args, &(flt_ot_current_tracer->proxy_log.loggers), kw_mod == KWM_NO, file, linenum, &err_log) == 0) {
+ FLT_OT_PARSE_ERR(&err, "'%s %s ...' : %s", args[0], args[1], err_log);
+ FLT_OT_FREE_CLEAR(err_log);
+
+ retval |= ERR_ABORT | ERR_ALERT;
+ } else {
+ flt_ot_current_tracer->logging |= FLT_OT_LOGGING_ON;
+ }
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_TRACER_CONFIG) {
+ retval = flt_ot_parse_cfg_file(&(flt_ot_current_tracer->config), file, linenum, args, &err, "configuration file");
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_TRACER_PLUGIN) {
+ retval = flt_ot_parse_cfg_file(&(flt_ot_current_tracer->plugin), file, linenum, args, &err, "plugin library");
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_TRACER_GROUPS) {
+ for (i = 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(i); i++)
+ if (flt_ot_conf_ph_init(args[i], linenum, &(flt_ot_current_tracer->ph_groups), &err) == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_TRACER_SCOPES) {
+ for (i = 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(i); i++)
+ if (flt_ot_conf_ph_init(args[i], linenum, &(flt_ot_current_tracer->ph_scopes), &err) == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_TRACER_ACL) {
+ if (strcasecmp(args[1], "or") == 0)
+ FLT_OT_PARSE_ERR(&err, "'%s %s ...' : invalid ACL name", args[0], args[1]);
+ else if (parse_acl((const char **)args + 1, &(flt_ot_current_tracer->acls), &err, &(flt_ot_current_config->proxy->conf.args), file, linenum) == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_TRACER_RATE_LIMIT) {
+ flt_ot_current_tracer->rate_limit = FLT_OT_FLOAT_U32(flt_ot_strtod(args[1], 0.0, FLT_OT_RATE_LIMIT_MAX, &err), FLT_OT_RATE_LIMIT_MAX);
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_TRACER_OPTION) {
+ if (strcmp(args[1], FLT_OT_PARSE_OPTION_DISABLED) == 0) {
+ flt_ot_current_tracer->flag_disabled = (kw_mod == KWM_NO) ? 0 : 1;
+ }
+ else if (strcmp(args[1], FLT_OT_PARSE_OPTION_HARDERR) == 0) {
+ flt_ot_current_tracer->flag_harderr = (kw_mod == KWM_NO) ? 0 : 1;
+ }
+ else if (strcmp(args[1], FLT_OT_PARSE_OPTION_NOLOGNORM) == 0) {
+ if (kw_mod == KWM_NO)
+ flt_ot_current_tracer->logging &= ~FLT_OT_LOGGING_NOLOGNORM;
+ else
+ flt_ot_current_tracer->logging |= FLT_OT_LOGGING_NOLOGNORM;
+ }
+ else
+ FLT_OT_PARSE_ERR(&err, "'%s' : unknown option '%s'", args[0], args[1]);
+ }
+#ifdef DEBUG_OT
+ else if (pdata->keyword == FLT_OT_PARSE_TRACER_DEBUG_LEVEL) {
+ flt_ot_debug.level = flt_ot_strtoll(args[1], 0, 255, &err);
+ }
+#else
+ else {
+ FLT_OT_PARSE_WARNING("'%s' : keyword ignored", file, linenum, args[0]);
+ }
+#endif
+
+ FLT_OT_PARSE_IFERR_ALERT();
+
+ if ((retval & ERR_CODE) && (flt_ot_current_tracer != NULL))
+ flt_ot_conf_tracer_free(&flt_ot_current_tracer);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_post_parse_cfg_tracer -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_post_parse_cfg_tracer(void)
+{
+ char errbuf[BUFSIZ] = "";
+ int retval = ERR_NONE;
+
+ FLT_OT_FUNC("");
+
+ if (flt_ot_current_tracer == NULL)
+ FLT_OT_RETURN_INT(retval);
+
+ flt_ot_current_config->tracer = flt_ot_current_tracer;
+
+ if (flt_ot_current_tracer->id == NULL)
+ FLT_OT_RETURN_INT(retval);
+
+ if (flt_ot_current_tracer->config == NULL) {
+ FLT_OT_POST_PARSE_ALERT("tracer '%s' has no configuration file specified", flt_ot_current_tracer->cfg_line, flt_ot_current_tracer->id);
+ } else {
+ flt_ot_current_tracer->cfgbuf = otc_file_read(flt_ot_current_tracer->config, "#", errbuf, sizeof(errbuf));
+ if (flt_ot_current_tracer->cfgbuf == NULL)
+ FLT_OT_POST_PARSE_ALERT("tracer '%s' %s", flt_ot_current_tracer->cfg_line, flt_ot_current_tracer->id, (*errbuf == '\0') ? "cannot load configuration file" : errbuf);
+ }
+
+ if (flt_ot_current_tracer->plugin == NULL)
+ FLT_OT_POST_PARSE_ALERT("tracer '%s' has no plugin library specified", flt_ot_current_tracer->cfg_line, flt_ot_current_tracer->id);
+
+ flt_ot_current_tracer = NULL;
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg_group -
+ *
+ * ARGUMENTS
+ * file -
+ * linenum -
+ * args -
+ * kw_mod -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg_group(const char *file, int linenum, char **args, int kw_mod)
+{
+#define FLT_OT_PARSE_GROUP_DEF(a,b,c,d,e,f,g) { FLT_OT_PARSE_GROUP_##a, b, FLT_OT_PARSE_INVALID_##c, d, e, f, g },
+ static const struct flt_ot_parse_data parse_data[] = { FLT_OT_PARSE_GROUP_DEFINES };
+#undef FLT_OT_PARSE_GROUP_DEF
+ const struct flt_ot_parse_data *pdata = NULL;
+ char *err = NULL;
+ int i, retval = ERR_NONE;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, 0x%08x", file, linenum, args, kw_mod);
+
+ if (flt_ot_parse_check_scope())
+ FLT_OT_RETURN_INT(retval);
+
+ retval = flt_ot_parse_cfg_check(file, linenum, args, flt_ot_current_group, parse_data, FLT_OT_TABLESIZE(parse_data), &pdata, &err);
+ if (retval & ERR_CODE) {
+ FLT_OT_PARSE_IFERR_ALERT();
+
+ FLT_OT_RETURN_INT(retval);
+ }
+
+ if (pdata->keyword == FLT_OT_PARSE_GROUP_ID) {
+ flt_ot_current_group = flt_ot_conf_group_init(args[1], linenum, &(flt_ot_current_config->groups), &err);
+ if (flt_ot_current_config == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_GROUP_SCOPES) {
+ for (i = 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(i); i++)
+ if (flt_ot_conf_ph_init(args[i], linenum, &(flt_ot_current_group->ph_scopes), &err) == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+
+ FLT_OT_PARSE_IFERR_ALERT();
+
+ if ((retval & ERR_CODE) && (flt_ot_current_group != NULL))
+ flt_ot_conf_group_free(&flt_ot_current_group);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_post_parse_cfg_group -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_post_parse_cfg_group(void)
+{
+ int retval = ERR_NONE;
+
+ FLT_OT_FUNC("");
+
+ if (flt_ot_current_group == NULL)
+ FLT_OT_RETURN_INT(retval);
+
+ /* Check that the group has at least one scope defined. */
+ if (LIST_ISEMPTY(&(flt_ot_current_group->ph_scopes)))
+ FLT_OT_POST_PARSE_ALERT("group '%s' has no defined scope(s)", flt_ot_current_group->cfg_line, flt_ot_current_group->id);
+
+ flt_ot_current_group = NULL;
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg_scope_ctx -
+ *
+ * ARGUMENTS
+ * args -
+ * cur_arg -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg_scope_ctx(char **args, int cur_arg, char **err)
+{
+ uint8_t flags = 0;
+ int retval = ERR_NONE;
+
+ FLT_OT_FUNC("%p, %d, %p:%p", args, cur_arg, FLT_OT_DPTR_ARGS(err));
+
+ if (strcmp(args[cur_arg], FLT_OT_PARSE_CTX_USE_HEADERS) == 0)
+ flags = FLT_OT_CTX_USE_HEADERS;
+#ifdef USE_OT_VARS
+ else if (strcmp(args[cur_arg], FLT_OT_PARSE_CTX_USE_VARS) == 0)
+ flags = FLT_OT_CTX_USE_VARS;
+#endif
+ else
+ FLT_OT_PARSE_ERR(err, "'%s' : invalid context storage type", args[0]);
+
+ if (flags == 0)
+ /* Do nothing. */;
+ else if (flt_ot_current_span->ctx_flags & flags)
+ FLT_OT_PARSE_ERR(err, "'%s' : %s already used", args[0], args[cur_arg]);
+ else
+ flt_ot_current_span->ctx_flags |= flags;
+
+ FLT_OT_DBG(2, "ctx_flags: 0x%02hhx (0x%02hhx)", flt_ot_current_span->ctx_flags, flags);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_acl -
+ *
+ * ARGUMENTS
+ * file -
+ * linenum -
+ * px -
+ * args -
+ * err -
+ * head -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static struct acl_cond *flt_ot_parse_acl(const char *file, int linenum, struct proxy *px, const char **args, char **err, struct list *head, ...)
+{
+ va_list ap;
+ int n = 0;
+ struct acl_cond *retptr = NULL;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, %p, %p:%p, %p, ...", file, linenum, px, args, FLT_OT_DPTR_ARGS(err), head);
+
+ for (va_start(ap, head); (retptr == NULL) && (head != NULL); head = va_arg(ap, typeof(head)), n++) {
+ retptr = build_acl_cond(file, linenum, head, px, args, (n == 0) ? err : NULL);
+ if (retptr != NULL)
+ FLT_OT_DBG(2, "ACL build done, using list %p %d", head, n);
+ }
+ va_end(ap);
+
+ if ((retptr != NULL) && (err != NULL))
+ FLT_OT_FREE_CLEAR(*err);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg_scope -
+ *
+ * ARGUMENTS
+ * file -
+ * linenum -
+ * args -
+ * kw_mod -
+ *
+ * DESCRIPTION
+ * Function used to load the scope block configuration.
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg_scope(const char *file, int linenum, char **args, int kw_mod)
+{
+#define FLT_OT_PARSE_SCOPE_DEF(a,b,c,d,e,f,g) { FLT_OT_PARSE_SCOPE_##a, b, FLT_OT_PARSE_INVALID_##c, d, e, f, g },
+ static const struct flt_ot_parse_data parse_data[] = { FLT_OT_PARSE_SCOPE_DEFINES };
+#undef FLT_OT_PARSE_SCOPE_DEF
+ const struct flt_ot_parse_data *pdata = NULL;
+ char *err = NULL;
+ int i, retval = ERR_NONE;
+
+ FLT_OT_FUNC("\"%s\", %d, %p, 0x%08x", file, linenum, args, kw_mod);
+
+ if (flt_ot_parse_check_scope())
+ FLT_OT_RETURN_INT(retval);
+
+ retval = flt_ot_parse_cfg_check(file, linenum, args, flt_ot_current_span, parse_data, FLT_OT_TABLESIZE(parse_data), &pdata, &err);
+ if (retval & ERR_CODE) {
+ FLT_OT_PARSE_IFERR_ALERT();
+
+ FLT_OT_RETURN_INT(retval);
+ }
+
+ if (pdata->keyword == FLT_OT_PARSE_SCOPE_ID) {
+ /* Initialization of a new scope. */
+ flt_ot_current_scope = flt_ot_conf_scope_init(args[1], linenum, &(flt_ot_current_config->scopes), &err);
+ if (flt_ot_current_scope == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_SCOPE_SPAN) {
+ /*
+ * Checking if this is the beginning of the definition of
+ * a new span.
+ */
+ if (flt_ot_current_span != NULL) {
+ FLT_OT_DBG(3, "span '%s' (done)", flt_ot_current_span->id);
+
+ flt_ot_current_span = NULL;
+ }
+
+ /* Initialization of a new span. */
+ flt_ot_current_span = flt_ot_conf_span_init(args[1], linenum, &(flt_ot_current_scope->spans), &err);
+
+ /*
+ * In case the span has a defined reference,
+ * the correctness of the arguments is checked here.
+ */
+ if (flt_ot_current_span == NULL) {
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+ else if (FLT_OT_ARG_ISVALID(2)) {
+ for (i = 2; (i < pdata->args_max) && FLT_OT_ARG_ISVALID(i); i++)
+ if (strcmp(args[i], FLT_OT_PARSE_SPAN_ROOT) == 0) {
+ if (flt_ot_current_span->flag_root)
+ FLT_OT_PARSE_ERR(&err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
+ else
+ flt_ot_current_span->flag_root = 1;
+ }
+ else if ((strcmp(args[i], FLT_OT_PARSE_SPAN_REF_CHILD) == 0) || (strcmp(args[i], FLT_OT_PARSE_SPAN_REF_FOLLOWS) == 0)) {
+ if (!FLT_OT_ARG_ISVALID(i + 1)) {
+ FLT_OT_PARSE_ERR(&err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
+ }
+ else if (strcmp(args[i++], FLT_OT_PARSE_SPAN_REF_CHILD) == 0) {
+ flt_ot_current_span->ref_type = otc_span_reference_child_of;
+ flt_ot_current_span->ref_id_len = strlen(args[i]);
+
+ retval = flt_ot_parse_strdup(&(flt_ot_current_span->ref_id), args[i], &err, args[1]);
+ }
+ else {
+ flt_ot_current_span->ref_type = otc_span_reference_follows_from;
+ flt_ot_current_span->ref_id_len = strlen(args[i]);
+
+ retval = flt_ot_parse_strdup(&(flt_ot_current_span->ref_id), args[i], &err, args[1]);
+ }
+ }
+ else {
+ FLT_OT_PARSE_ERR(&err, "'%s' : invalid argument (use '%s%s')", args[i], pdata->name, pdata->usage);
+ }
+ }
+ else {
+ /*
+ * This is not a faulty configuration, only such a case
+ * will be logged.
+ */
+ FLT_OT_DBG(3, "new span '%s' without reference", flt_ot_current_span->id);
+ }
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_SCOPE_TAG) {
+ retval = flt_ot_parse_cfg_sample(file, linenum, args, &(flt_ot_current_span->tags), &err);
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_SCOPE_LOG) {
+ retval = flt_ot_parse_cfg_sample(file, linenum, args, &(flt_ot_current_span->logs), &err);
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_SCOPE_BAGGAGE) {
+ retval = flt_ot_parse_cfg_sample(file, linenum, args, &(flt_ot_current_span->baggages), &err);
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_SCOPE_INJECT) {
+ /*
+ * Automatic context name generation can be specified here
+ * if the contents of the FLT_OT_PARSE_CTX_AUTONAME macro
+ * are used as the name. In that case, if the context is
+ * after a particular event, it gets its name; otherwise
+ * it gets the name of the current span.
+ */
+ if (flt_ot_current_span->ctx_id != NULL)
+ FLT_OT_PARSE_ERR(&err, "'%s' : only one context per span is allowed", args[1]);
+ else if (strcmp(args[1], FLT_OT_PARSE_CTX_AUTONAME) != 0)
+ retval = flt_ot_parse_strdup(&(flt_ot_current_span->ctx_id), args[1], &err, args[0]);
+ else if (flt_ot_current_scope->event != FLT_OT_EVENT_REQ_NONE)
+ retval = flt_ot_parse_strdup(&(flt_ot_current_span->ctx_id), flt_ot_event_data[flt_ot_current_scope->event].name, &err, args[0]);
+ else
+ retval = flt_ot_parse_strdup(&(flt_ot_current_span->ctx_id), flt_ot_current_span->id, &err, args[0]);
+
+ if (flt_ot_current_span->ctx_id != NULL) {
+ flt_ot_current_span->ctx_id_len = strlen(flt_ot_current_span->ctx_id);
+
+ /*
+ * Here is checked the context storage type; which, if
+ * not explicitly specified, is set to HTTP headers.
+ *
+ * It is possible to use both types of context storage
+ * at the same time.
+ */
+ if (FLT_OT_ARG_ISVALID(2)) {
+ retval = flt_ot_parse_cfg_scope_ctx(args, 2, &err);
+ if (!(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(3))
+ retval = flt_ot_parse_cfg_scope_ctx(args, 3, &err);
+ } else {
+ flt_ot_current_span->ctx_flags = FLT_OT_CTX_USE_HEADERS;
+ }
+ }
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_SCOPE_EXTRACT) {
+ struct flt_ot_conf_context *conf_ctx;
+
+ /*
+ * Here is checked the context storage type; which, if
+ * not explicitly specified, is set to HTTP headers.
+ */
+ conf_ctx = flt_ot_conf_context_init(args[1], linenum, &(flt_ot_current_scope->contexts), &err);
+ if (conf_ctx == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ else if (!FLT_OT_ARG_ISVALID(2))
+ conf_ctx->flags = FLT_OT_CTX_USE_HEADERS;
+ else if (strcmp(args[2], FLT_OT_PARSE_CTX_USE_HEADERS) == 0)
+ conf_ctx->flags = FLT_OT_CTX_USE_HEADERS;
+#ifdef USE_OT_VARS
+ else if (strcmp(args[2], FLT_OT_PARSE_CTX_USE_VARS) == 0)
+ conf_ctx->flags = FLT_OT_CTX_USE_VARS;
+#endif
+ else
+ FLT_OT_PARSE_ERR(&err, "'%s' : invalid context storage type", args[2]);
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_SCOPE_FINISH) {
+ retval = flt_ot_parse_cfg_str(file, linenum, args, &(flt_ot_current_scope->finish), &err);
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_SCOPE_ACL) {
+ if (strcasecmp(args[1], "or") == 0)
+ FLT_OT_PARSE_ERR(&err, "'%s %s ...' : invalid ACL name", args[0], args[1]);
+ else if (parse_acl((const char **)args + 1, &(flt_ot_current_scope->acls), &err, &(flt_ot_current_config->proxy->conf.args), file, linenum) == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+ else if (pdata->keyword == FLT_OT_PARSE_SCOPE_EVENT) {
+ /* Scope can only have one event defined. */
+ if (flt_ot_current_scope->event != FLT_OT_EVENT_REQ_NONE) {
+ FLT_OT_PARSE_ERR(&err, "'%s' : event already set", flt_ot_current_scope->id);
+ } else {
+ /* Check the event name. */
+ for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_event_data); i++)
+ if (strcmp(flt_ot_event_data[i].name, args[1]) == 0) {
+ flt_ot_current_scope->event = i;
+
+ break;
+ }
+
+ /*
+ * The event can have some condition defined and this
+ * is checked here.
+ */
+ if (flt_ot_current_scope->event == FLT_OT_EVENT_REQ_NONE) {
+ FLT_OT_PARSE_ERR(&err, "'%s' : unknown event", args[1]);
+ }
+ else if (!FLT_OT_ARG_ISVALID(2)) {
+ /* Do nothing. */
+ }
+ else if ((strcmp(args[2], FLT_OT_CONDITION_IF) == 0) || (strcmp(args[2], FLT_OT_CONDITION_UNLESS) == 0)) {
+ /*
+ * We will first try to build ACL condition using
+ * local settings and then if that fails, using
+ * global settings (from tracer block). If it
+ * also fails, then try to use ACL defined in
+ * the HAProxy configuration.
+ */
+ flt_ot_current_scope->cond = flt_ot_parse_acl(file, linenum, flt_ot_current_config->proxy, (const char **)args + 2, &err, &(flt_ot_current_scope->acls), &(flt_ot_current_config->tracer->acls), &(flt_ot_current_config->proxy->acl), NULL);
+ if (flt_ot_current_scope->cond == NULL)
+ retval |= ERR_ABORT | ERR_ALERT;
+ }
+ else {
+ FLT_OT_PARSE_ERR(&err, "'%s' : expects either 'if' or 'unless' followed by a condition but found '%s'", args[1], args[2]);
+ }
+
+ if (!(retval & ERR_CODE))
+ FLT_OT_DBG(3, "event '%s'", args[1]);
+ }
+ }
+
+ FLT_OT_PARSE_IFERR_ALERT();
+
+ if ((retval & ERR_CODE) && (flt_ot_current_scope != NULL)) {
+ flt_ot_conf_scope_free(&flt_ot_current_scope);
+
+ flt_ot_current_span = NULL;
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_post_parse_cfg_scope -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * In this function the correctness of the complete scope block is examined.
+ * This does not mean that all elements are checked here, but only those for
+ * which it has not been possible to establish their complete correctness in
+ * the function flt_ot_parse_cfg_scope().
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_post_parse_cfg_scope(void)
+{
+ struct flt_ot_conf_span *conf_span;
+ int retval = ERR_NONE;
+
+ FLT_OT_FUNC("");
+
+ if (flt_ot_current_scope == NULL)
+ FLT_OT_RETURN_INT(retval);
+
+ /* If span context inject is used, check that this is possible. */
+ list_for_each_entry(conf_span, &(flt_ot_current_scope->spans), list)
+ if ((conf_span->ctx_id != NULL) && (conf_span->ctx_flags & FLT_OT_CTX_USE_HEADERS))
+ if (!flt_ot_event_data[flt_ot_current_scope->event].flag_http_inject)
+ FLT_OT_POST_PARSE_ALERT("inject '%s' : cannot use on this event", conf_span->cfg_line, conf_span->ctx_id);
+
+ if (retval & ERR_CODE)
+ flt_ot_conf_scope_free(&flt_ot_current_scope);
+
+ flt_ot_current_scope = NULL;
+ flt_ot_current_span = NULL;
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse_cfg -
+ *
+ * ARGUMENTS
+ * conf -
+ * flt_name -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse_cfg(struct flt_ot_conf *conf, const char *flt_name, char **err)
+{
+ struct list backup_sections;
+ int retval = ERR_ABORT | ERR_ALERT;
+
+ FLT_OT_FUNC("%p, \"%s\", %p:%p", conf, flt_name, FLT_OT_DPTR_ARGS(err));
+
+ flt_ot_current_config = conf;
+
+ /* Backup sections. */
+ LIST_INIT(&backup_sections);
+ cfg_backup_sections(&backup_sections);
+
+ /* Register new OT sections and parse the OT filter configuration file. */
+ if (!cfg_register_section(FLT_OT_PARSE_SECTION_TRACER_ID, flt_ot_parse_cfg_tracer, flt_ot_post_parse_cfg_tracer))
+ /* Do nothing. */;
+ else if (!cfg_register_section(FLT_OT_PARSE_SECTION_GROUP_ID, flt_ot_parse_cfg_group, flt_ot_post_parse_cfg_group))
+ /* Do nothing. */;
+ else if (!cfg_register_section(FLT_OT_PARSE_SECTION_SCOPE_ID, flt_ot_parse_cfg_scope, flt_ot_post_parse_cfg_scope))
+ /* Do nothing. */;
+ else if (access(conf->cfg_file, R_OK) == -1)
+ FLT_OT_PARSE_ERR(err, "'%s' : %s", conf->cfg_file, strerror(errno));
+ else
+ retval = readcfgfile(conf->cfg_file);
+
+ /* Unregister OT sections and restore previous sections. */
+ cfg_unregister_sections();
+ cfg_restore_sections(&backup_sections);
+
+ flt_ot_current_config = NULL;
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_parse -
+ *
+ * ARGUMENTS
+ * args -
+ * cur_arg -
+ * px -
+ * fconf -
+ * err -
+ * private -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns ERR_NONE (== 0) in case of success,
+ * or a combination of ERR_* flags if an error is encountered.
+ */
+static int flt_ot_parse(char **args, int *cur_arg, struct proxy *px, struct flt_conf *fconf, char **err, void *private)
+{
+ struct flt_ot_conf *conf = NULL;
+ int pos, retval = ERR_NONE;
+
+#ifdef DEBUG_OT
+ FLT_OT_RUN_ONCE(
+# ifndef DEBUG_OT_SYSTIME
+ (void)memcpy(&(flt_ot_debug.start), &date, sizeof(flt_ot_debug.start));
+# endif
+
+ flt_ot_debug.level = FLT_OT_DEBUG_LEVEL;
+ );
+#endif
+
+ FLT_OT_FUNC("%p, %p, %p, %p, %p:%p, %p", args, cur_arg, px, fconf, FLT_OT_DPTR_ARGS(err), private);
+
+#ifdef OTC_DBG_MEM
+ FLT_OT_RUN_ONCE(
+ if (otc_dbg_mem_init(&dbg_mem, dbg_mem_data, FLT_OT_TABLESIZE(dbg_mem_data), 0xff) == -1) {
+ FLT_OT_PARSE_ERR(err, "cannot initialize memory debugger");
+
+ FLT_OT_RETURN_INT(retval);
+ }
+ );
+#endif
+
+ FLT_OT_ARGS_DUMP();
+
+ conf = flt_ot_conf_init(px);
+ if (conf == NULL) {
+ FLT_OT_PARSE_ERR(err, "'%s' : out of memory", args[*cur_arg]);
+
+ FLT_OT_RETURN_INT(retval);
+ }
+
+ for (pos = *cur_arg + 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(pos); pos++) {
+ FLT_OT_DBG(3, "args[%d:2] : { '%s' '%s' }", pos, args[pos], args[pos + 1]);
+
+ if (strcmp(args[pos], FLT_OT_OPT_FILTER_ID) == 0) {
+ retval = flt_ot_parse_keyword(&(conf->id), args, *cur_arg, pos, err, "name");
+ pos++;
+ }
+ else if (strcmp(args[pos], FLT_OT_OPT_CONFIG) == 0) {
+ retval = flt_ot_parse_keyword(&(conf->cfg_file), args, *cur_arg, pos, err, "configuration file");
+ if (!(retval & ERR_CODE))
+ retval = flt_ot_parse_cfg(conf, args[*cur_arg], err);
+ pos++;
+ }
+ else {
+ FLT_OT_PARSE_ERR(err, "'%s' : unknown keyword '%s'", args[*cur_arg], args[pos]);
+ }
+ }
+
+ /* If the OpenTracing filter ID is not set, use default name. */
+ if (!(retval & ERR_CODE) && (conf->id == NULL)) {
+ ha_warning("parsing : " FLT_OT_FMT_TYPE FLT_OT_FMT_NAME "'no filter id set, using default id '%s'\n", FLT_OT_OPT_FILTER_ID_DEFAULT);
+
+ retval = flt_ot_parse_strdup(&(conf->id), FLT_OT_OPT_FILTER_ID_DEFAULT, err, args[*cur_arg]);
+ }
+
+ if (!(retval & ERR_CODE) && (conf->cfg_file == NULL))
+ FLT_OT_PARSE_ERR(err, "'%s' : no configuration file specified", args[*cur_arg]);
+
+ if (retval & ERR_CODE) {
+ flt_ot_conf_free(&conf);
+ } else {
+ fconf->id = ot_flt_id;
+ fconf->ops = &flt_ot_ops;
+ fconf->conf = conf;
+
+ *cur_arg = pos;
+
+ FLT_OT_DBG(3, "filter set: id '%s', config '%s'", conf->id, conf->cfg_file);
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/* Declare the filter parser for FLT_OT_OPT_NAME keyword. */
+static struct flt_kw_list flt_kws = { FLT_OT_SCOPE, { }, {
+ { FLT_OT_OPT_NAME, flt_ot_parse, NULL },
+ { NULL, NULL, NULL },
+ }
+};
+
+INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/pool.c b/addons/ot/src/pool.c
new file mode 100644
index 0000000..fbcdbfc
--- /dev/null
+++ b/addons/ot/src/pool.c
@@ -0,0 +1,223 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+/***
+ * NAME
+ * flt_ot_pool_alloc -
+ *
+ * ARGUMENTS
+ * pool -
+ * size -
+ * flag_clear -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *flt_ot_pool_alloc(struct pool_head *pool, size_t size, bool flag_clear, char **err)
+{
+ void *retptr;
+
+ FLT_OT_FUNC("%p, %zu, %hhu, %p:%p", pool, size, flag_clear, FLT_OT_DPTR_ARGS(err));
+
+ if (pool != NULL) {
+ retptr = pool_alloc(pool);
+ if (retptr != NULL)
+ FLT_OT_DBG(2, "POOL_ALLOC: %s:%d(%p %zu)", __func__, __LINE__, retptr, FLT_OT_DEREF(pool, size, size));
+ } else {
+ retptr = FLT_OT_MALLOC(size);
+ }
+
+ if (retptr == NULL)
+ FLT_OT_ERR("out of memory");
+ else if (flag_clear)
+ (void)memset(retptr, 0, size);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_pool_strndup -
+ *
+ * ARGUMENTS
+ * pool -
+ * s -
+ * size -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+void *flt_ot_pool_strndup(struct pool_head *pool, const char *s, size_t size, char **err)
+{
+ void *retptr;
+
+ FLT_OT_FUNC("%p, \"%.*s\", %zu, %p:%p", pool, (int)size, s, size, FLT_OT_DPTR_ARGS(err));
+
+ if (pool != NULL) {
+ retptr = pool_alloc(pool);
+ if (retptr != NULL) {
+ (void)memcpy(retptr, s, MIN(pool->size - 1, size));
+
+ ((uint8_t *)retptr)[MIN(pool->size - 1, size)] = '\0';
+ }
+ } else {
+ retptr = FLT_OT_STRNDUP(s, size);
+ }
+
+ if (retptr != NULL)
+ FLT_OT_DBG(2, "POOL_STRNDUP: %s:%d(%p %zu)", __func__, __LINE__, retptr, FLT_OT_DEREF(pool, size, size));
+ else
+ FLT_OT_ERR("out of memory");
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_pool_free -
+ *
+ * ARGUMENTS
+ * pool -
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_pool_free(struct pool_head *pool, void **ptr)
+{
+ FLT_OT_FUNC("%p, %p:%p", pool, FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG(2, "POOL_FREE: %s:%d(%p %u)", __func__, __LINE__, *ptr, FLT_OT_DEREF(pool, size, 0));
+
+ if (pool != NULL)
+ pool_free(pool, *ptr);
+ else
+ FLT_OT_FREE(*ptr);
+
+ *ptr = NULL;
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_trash_alloc -
+ *
+ * ARGUMENTS
+ * flag_clear -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct buffer *flt_ot_trash_alloc(bool flag_clear, char **err)
+{
+ struct buffer *retptr;
+
+ FLT_OT_FUNC("%hhu, %p:%p", flag_clear, FLT_OT_DPTR_ARGS(err));
+
+#ifdef USE_TRASH_CHUNK
+ retptr = alloc_trash_chunk();
+ if (retptr != NULL)
+ FLT_OT_DBG(2, "TRASH_ALLOC: %s:%d(%p %zu)", __func__, __LINE__, retptr, retptr->size);
+#else
+ retptr = FLT_OT_MALLOC(sizeof(*retptr));
+ if (retptr != NULL) {
+ chunk_init(retptr, FLT_OT_MALLOC(global.tune.bufsize), global.tune.bufsize);
+ if (retptr->area == NULL)
+ FLT_OT_FREE_CLEAR(retptr);
+ else
+ *(retptr->area) = '\0';
+ }
+#endif
+
+ if (retptr == NULL)
+ FLT_OT_ERR("out of memory");
+ else if (flag_clear)
+ (void)memset(retptr->area, 0, retptr->size);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_trash_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_trash_free(struct buffer **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG(2, "TRASH_FREE: %s:%d(%p %zu)", __func__, __LINE__, *ptr, (*ptr)->size);
+
+#ifdef USE_TRASH_CHUNK
+ free_trash_chunk(*ptr);
+#else
+ FLT_OT_FREE((*ptr)->area);
+ FLT_OT_FREE(*ptr);
+#endif
+
+ *ptr = NULL;
+
+ FLT_OT_RETURN();
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/scope.c b/addons/ot/src/scope.c
new file mode 100644
index 0000000..efe8fe2
--- /dev/null
+++ b/addons/ot/src/scope.c
@@ -0,0 +1,634 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+static struct pool_head *pool_head_ot_scope_span __read_mostly = NULL;
+static struct pool_head *pool_head_ot_scope_context __read_mostly = NULL;
+static struct pool_head *pool_head_ot_runtime_context __read_mostly = NULL;
+
+#ifdef USE_POOL_OT_SCOPE_SPAN
+REGISTER_POOL(&pool_head_ot_scope_span, "ot_scope_span", sizeof(struct flt_ot_scope_span));
+#endif
+#ifdef USE_POOL_OT_SCOPE_CONTEXT
+REGISTER_POOL(&pool_head_ot_scope_context, "ot_scope_context", sizeof(struct flt_ot_scope_context));
+#endif
+#ifdef USE_POOL_OT_RUNTIME_CONTEXT
+REGISTER_POOL(&pool_head_ot_runtime_context, "ot_runtime_context", sizeof(struct flt_ot_runtime_context));
+#endif
+
+
+#ifdef DEBUG_OT
+
+/***
+ * NAME
+ * flt_ot_pools_info -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_pools_info(void)
+{
+ /*
+ * In case we have some error in the configuration file,
+ * it is possible that this pool was not initialized.
+ */
+#ifdef USE_POOL_BUFFER
+ FLT_OT_DBG(2, "sizeof_pool(buffer) = %u", FLT_OT_DEREF(pool_head_buffer, size, 0));
+#endif
+#ifdef USE_TRASH_CHUNK
+ FLT_OT_DBG(2, "sizeof_pool(trash) = %u", FLT_OT_DEREF(pool_head_trash, size, 0));
+#endif
+
+#ifdef USE_POOL_OT_SCOPE_SPAN
+ FLT_OT_DBG(2, "sizeof_pool(ot_scope_span) = %u", pool_head_ot_scope_span->size);
+#endif
+#ifdef USE_POOL_OT_SCOPE_CONTEXT
+ FLT_OT_DBG(2, "sizeof_pool(ot_scope_context) = %u", pool_head_ot_scope_context->size);
+#endif
+#ifdef USE_POOL_OT_RUNTIME_CONTEXT
+ FLT_OT_DBG(2, "sizeof_pool(ot_runtime_context) = %u", pool_head_ot_runtime_context->size);
+#endif
+}
+
+#endif /* DEBUG_OT */
+
+
+/***
+ * NAME
+ * flt_ot_runtime_context_init -
+ *
+ * ARGUMENTS
+ * s -
+ * f -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_runtime_context *flt_ot_runtime_context_init(struct stream *s, struct filter *f, char **err)
+{
+ const struct flt_ot_conf *conf = FLT_OT_CONF(f);
+ struct buffer uuid;
+ struct flt_ot_runtime_context *retptr = NULL;
+
+ FLT_OT_FUNC("%p, %p, %p:%p", s, f, FLT_OT_DPTR_ARGS(err));
+
+ retptr = flt_ot_pool_alloc(pool_head_ot_runtime_context, sizeof(*retptr), 1, err);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ retptr->stream = s;
+ retptr->filter = f;
+ retptr->flag_harderr = conf->tracer->flag_harderr;
+ retptr->flag_disabled = conf->tracer->flag_disabled;
+ retptr->logging = conf->tracer->logging;
+ LIST_INIT(&(retptr->spans));
+ LIST_INIT(&(retptr->contexts));
+
+ uuid = b_make(retptr->uuid, sizeof(retptr->uuid), 0, 0);
+ ha_generate_uuid(&uuid);
+
+#ifdef USE_OT_VARS
+ /*
+ * The HAProxy variable 'sess.ot.uuid' is registered here,
+ * after which its value is set to runtime context UUID.
+ */
+ if (flt_ot_var_register(FLT_OT_VAR_UUID, err) != -1)
+ (void)flt_ot_var_set(s, FLT_OT_VAR_UUID, retptr->uuid, SMP_OPT_DIR_REQ, err);
+#endif
+
+ FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_runtime_context_free -
+ *
+ * ARGUMENTS
+ * f -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_runtime_context_free(struct filter *f)
+{
+ struct flt_ot_runtime_context *rt_ctx = f->ctx;
+
+ FLT_OT_FUNC("%p", f);
+
+ if (rt_ctx == NULL)
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx);
+
+ if (!LIST_ISEMPTY(&(rt_ctx->spans))) {
+ struct timespec ts;
+ struct flt_ot_scope_span *span, *span_back;
+
+ /* All spans should be completed at the same time. */
+ (void)clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list) {
+ ot_span_finish(&(span->span), &ts, NULL, NULL, NULL);
+ flt_ot_scope_span_free(&span);
+ }
+ }
+
+ if (!LIST_ISEMPTY(&(rt_ctx->contexts))) {
+ struct flt_ot_scope_context *ctx, *ctx_back;
+
+ list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list)
+ flt_ot_scope_context_free(&ctx);
+ }
+
+ flt_ot_pool_free(pool_head_ot_runtime_context, &(f->ctx));
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_scope_span_init -
+ *
+ * ARGUMENTS
+ * rt_ctx -
+ * id -
+ * id_len -
+ * ref_type -
+ * ref_id -
+ * ref_id_len -
+ * dir -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_scope_span *flt_ot_scope_span_init(struct flt_ot_runtime_context *rt_ctx, const char *id, size_t id_len, otc_span_reference_type_t ref_type, const char *ref_id, size_t ref_id_len, uint dir, char **err)
+{
+ struct otc_span *ref_span = NULL;
+ struct otc_span_context *ref_ctx = NULL;
+ struct flt_ot_scope_span *span, *retptr = NULL;
+ struct flt_ot_scope_context *ctx;
+
+ FLT_OT_FUNC("%p, \"%s\", %zu, %d, \"%s\", %zu, %u, %p:%p", rt_ctx, id, id_len, ref_type, ref_id, ref_id_len, dir, FLT_OT_DPTR_ARGS(err));
+
+ if ((rt_ctx == NULL) || (id == NULL))
+ FLT_OT_RETURN_PTR(retptr);
+
+ list_for_each_entry(span, &(rt_ctx->spans), list)
+ if ((span->id_len == id_len) && (memcmp(span->id, id, id_len) == 0)) {
+ FLT_OT_DBG(2, "found span %p", span);
+
+ FLT_OT_RETURN_PTR(span);
+ }
+
+ if (ref_id != NULL) {
+ list_for_each_entry(span, &(rt_ctx->spans), list)
+ if ((span->id_len == ref_id_len) && (memcmp(span->id, ref_id, ref_id_len) == 0)) {
+ ref_span = span->span;
+
+ break;
+ }
+
+ if (ref_span != NULL) {
+ FLT_OT_DBG(2, "found referenced span %p", span);
+ } else {
+ list_for_each_entry(ctx, &(rt_ctx->contexts), list)
+ if ((ctx->id_len == ref_id_len) && (memcmp(ctx->id, ref_id, ref_id_len) == 0)) {
+ ref_ctx = ctx->context;
+
+ break;
+ }
+
+ if (ref_ctx != NULL) {
+ FLT_OT_DBG(2, "found referenced context %p", ctx);
+ } else {
+ FLT_OT_ERR("cannot find referenced span/context '%s'", ref_id);
+
+ FLT_OT_RETURN_PTR(retptr);
+ }
+ }
+ }
+
+ retptr = flt_ot_pool_alloc(pool_head_ot_scope_span, sizeof(*retptr), 1, err);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ retptr->id = id;
+ retptr->id_len = id_len;
+ retptr->smp_opt_dir = dir;
+ retptr->ref_type = ref_type;
+ retptr->ref_span = ref_span;
+ retptr->ref_ctx = ref_ctx;
+ LIST_INSERT(&(rt_ctx->spans), &(retptr->list));
+
+ FLT_OT_DBG_SCOPE_SPAN("new span ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_scope_span_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_scope_span_free(struct flt_ot_scope_span **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_SCOPE_SPAN("", *ptr);
+
+ /* If the span is still active, do nothing. */
+ if ((*ptr)->span != NULL) {
+ FLT_OT_DBG(2, "cannot finish active span");
+
+ FLT_OT_RETURN();
+ }
+
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ flt_ot_pool_free(pool_head_ot_scope_span, (void **)ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_scope_context_init -
+ *
+ * ARGUMENTS
+ * rt_ctx -
+ * tracer -
+ * id -
+ * id_len -
+ * text_map -
+ * dir -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct flt_ot_scope_context *flt_ot_scope_context_init(struct flt_ot_runtime_context *rt_ctx, struct otc_tracer *tracer, const char *id, size_t id_len, const struct otc_text_map *text_map, uint dir, char **err)
+{
+ struct otc_http_headers_reader reader;
+ struct otc_span_context *span_ctx;
+ struct flt_ot_scope_context *retptr = NULL;
+
+ FLT_OT_FUNC("%p, %p, \"%s\", %zu, %p, %u, %p:%p", rt_ctx, tracer, id, id_len, text_map, dir, FLT_OT_DPTR_ARGS(err));
+
+ if ((rt_ctx == NULL) || (tracer == NULL) || (id == NULL) || (text_map == NULL))
+ FLT_OT_RETURN_PTR(retptr);
+
+ list_for_each_entry(retptr, &(rt_ctx->contexts), list)
+ if ((retptr->id_len == id_len) && (memcmp(retptr->id, id, id_len) == 0)) {
+ FLT_OT_DBG(2, "found context %p", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+ }
+
+ retptr = flt_ot_pool_alloc(pool_head_ot_scope_context, sizeof(*retptr), 1, err);
+ if (retptr == NULL)
+ FLT_OT_RETURN_PTR(retptr);
+
+ span_ctx = ot_extract_http_headers(tracer, &reader, text_map, err);
+ if (span_ctx == NULL) {
+ flt_ot_scope_context_free(&retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+ }
+
+ retptr->id = id;
+ retptr->id_len = id_len;
+ retptr->smp_opt_dir = dir;
+ retptr->context = span_ctx;
+ LIST_INSERT(&(rt_ctx->contexts), &(retptr->list));
+
+ FLT_OT_DBG_SCOPE_CONTEXT("new context ", retptr);
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+
+/***
+ * NAME
+ * flt_ot_scope_context_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_scope_context_free(struct flt_ot_scope_context **ptr)
+{
+ FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
+
+ if ((ptr == NULL) || (*ptr == NULL))
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_SCOPE_CONTEXT("", *ptr);
+
+ if ((*ptr)->context != NULL)
+ (*ptr)->context->destroy(&((*ptr)->context));
+
+ FLT_OT_LIST_DEL(&((*ptr)->list));
+ flt_ot_pool_free(pool_head_ot_scope_context, (void **)ptr);
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_scope_data_free -
+ *
+ * ARGUMENTS
+ * ptr -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_scope_data_free(struct flt_ot_scope_data *ptr)
+{
+ int i;
+
+ FLT_OT_FUNC("%p", ptr);
+
+ if (ptr == NULL)
+ FLT_OT_RETURN();
+
+ FLT_OT_DBG_SCOPE_DATA("", ptr);
+
+ for (i = 0; i < ptr->num_tags; i++)
+ if (ptr->tags[i].value.type == otc_value_string)
+ FLT_OT_FREE_VOID(ptr->tags[i].value.value.string_value);
+ otc_text_map_destroy(&(ptr->baggage), OTC_TEXT_MAP_FREE_VALUE);
+ for (i = 0; i < ptr->num_log_fields; i++)
+ if (ptr->log_fields[i].value.type == otc_value_string)
+ FLT_OT_FREE_VOID(ptr->log_fields[i].value.value.string_value);
+
+ (void)memset(ptr, 0, sizeof(*ptr));
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_scope_finish_mark -
+ *
+ * ARGUMENTS
+ * rt_ctx -
+ * id -
+ * id_len -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int flt_ot_scope_finish_mark(const struct flt_ot_runtime_context *rt_ctx, const char *id, size_t id_len)
+{
+ struct flt_ot_scope_span *span;
+ struct flt_ot_scope_context *ctx;
+ int span_cnt = 0, ctx_cnt = 0, retval;
+
+ FLT_OT_FUNC("%p, \"%s\", %zu", rt_ctx, id, id_len);
+
+ if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_ALL, id, id_len)) {
+ list_for_each_entry(span, &(rt_ctx->spans), list) {
+ span->flag_finish = 1;
+ span_cnt++;
+ }
+
+ list_for_each_entry(ctx, &(rt_ctx->contexts), list) {
+ ctx->flag_finish = 1;
+ ctx_cnt++;
+ }
+
+ FLT_OT_DBG(2, "marked %d span(s), %d context(s)", span_cnt, ctx_cnt);
+ }
+ else if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_REQ, id, id_len)) {
+ list_for_each_entry(span, &(rt_ctx->spans), list)
+ if (span->smp_opt_dir == SMP_OPT_DIR_REQ) {
+ span->flag_finish = 1;
+ span_cnt++;
+ }
+
+ list_for_each_entry(ctx, &(rt_ctx->contexts), list)
+ if (ctx->smp_opt_dir == SMP_OPT_DIR_REQ) {
+ ctx->flag_finish = 1;
+ span_cnt++;
+ }
+
+ FLT_OT_DBG(2, "marked REQuest channel %d span(s), %d context(s)", span_cnt, ctx_cnt);
+ }
+ else if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_RES, id, id_len)) {
+ list_for_each_entry(span, &(rt_ctx->spans), list)
+ if (span->smp_opt_dir == SMP_OPT_DIR_RES) {
+ span->flag_finish = 1;
+ span_cnt++;
+ }
+
+ list_for_each_entry(ctx, &(rt_ctx->contexts), list)
+ if (ctx->smp_opt_dir == SMP_OPT_DIR_RES) {
+ ctx->flag_finish = 1;
+ ctx_cnt++;
+ }
+
+ FLT_OT_DBG(2, "marked RESponse channel %d span(s), %d context(s)", span_cnt, ctx_cnt);
+ }
+ else {
+ list_for_each_entry(span, &(rt_ctx->spans), list)
+ if ((span->id_len == id_len) && (memcmp(span->id, id, id_len) == 0)) {
+ span->flag_finish = 1;
+ span_cnt++;
+
+ break;
+ }
+
+ list_for_each_entry(ctx, &(rt_ctx->contexts), list)
+ if ((ctx->id_len == id_len) && (memcmp(ctx->id, id, id_len) == 0)) {
+ ctx->flag_finish = 1;
+ ctx_cnt++;
+
+ break;
+ }
+
+ if (span_cnt > 0)
+ FLT_OT_DBG(2, "marked span '%s'", id);
+ if (ctx_cnt > 0)
+ FLT_OT_DBG(2, "marked context '%s'", id);
+ if ((span_cnt + ctx_cnt) == 0)
+ FLT_OT_DBG(2, "cannot find span/context '%s'", id);
+ }
+
+ retval = span_cnt + ctx_cnt;
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_scope_finish_marked -
+ *
+ * ARGUMENTS
+ * rt_ctx -
+ * ts_finish -
+ *
+ * DESCRIPTION
+ * Finish marked spans.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_scope_finish_marked(const struct flt_ot_runtime_context *rt_ctx, const struct timespec *ts_finish)
+{
+ struct flt_ot_scope_span *span;
+ struct flt_ot_scope_context *ctx;
+
+ FLT_OT_FUNC("%p, %p", rt_ctx, ts_finish);
+
+ list_for_each_entry(span, &(rt_ctx->spans), list)
+ if (span->flag_finish) {
+ FLT_OT_DBG_SCOPE_SPAN("finishing span ", span);
+
+ ot_span_finish(&(span->span), ts_finish, NULL, NULL, NULL);
+
+ span->flag_finish = 0;
+ }
+
+ list_for_each_entry(ctx, &(rt_ctx->contexts), list)
+ if (ctx->flag_finish) {
+ FLT_OT_DBG_SCOPE_CONTEXT("finishing context ", ctx);
+
+ if (ctx->context != NULL)
+ ctx->context->destroy(&(ctx->context));
+
+ ctx->flag_finish = 0;
+ }
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_scope_free_unused -
+ *
+ * ARGUMENTS
+ * rt_ctx -
+ * chn -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_scope_free_unused(struct flt_ot_runtime_context *rt_ctx, struct channel *chn)
+{
+ FLT_OT_FUNC("%p", rt_ctx);
+
+ if (rt_ctx == NULL)
+ FLT_OT_RETURN();
+
+ if (!LIST_ISEMPTY(&(rt_ctx->spans))) {
+ struct flt_ot_scope_span *span, *span_back;
+
+ list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list)
+ if (span->span == NULL)
+ flt_ot_scope_span_free(&span);
+ }
+
+ if (!LIST_ISEMPTY(&(rt_ctx->contexts))) {
+ struct flt_ot_scope_context *ctx, *ctx_back;
+
+ list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list)
+ if (ctx->context == NULL) {
+ /*
+ * All headers and variables associated with
+ * the context in question should be deleted.
+ */
+ (void)flt_ot_http_headers_remove(chn, ctx->id, NULL);
+#ifdef USE_OT_VARS
+ (void)flt_ot_vars_unset(rt_ctx->stream, FLT_OT_VARS_SCOPE, ctx->id, ctx->smp_opt_dir, NULL);
+#endif
+
+ flt_ot_scope_context_free(&ctx);
+ }
+ }
+
+ FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx);
+
+ FLT_OT_RETURN();
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/util.c b/addons/ot/src/util.c
new file mode 100644
index 0000000..fd04016
--- /dev/null
+++ b/addons/ot/src/util.c
@@ -0,0 +1,815 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+#ifdef DEBUG_OT
+
+/***
+ * NAME
+ * flt_ot_args_dump -
+ *
+ * ARGUMENTS
+ * args -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_args_dump(char **args)
+{
+ int i, argc;
+
+ argc = flt_ot_args_count(args);
+
+ (void)fprintf(stderr, FLT_OT_DBG_FMT("%.*sargs[%d]: { '%s' "), dbg_indent_level, FLT_OT_DBG_INDENT, argc, args[0]);
+
+ for (i = 1; i < argc; i++)
+ (void)fprintf(stderr, "'%s' ", args[i]);
+
+ (void)fprintf(stderr, "}\n");
+}
+
+
+/***
+ * NAME
+ * flt_ot_filters_dump -
+ *
+ * ARGUMENTS
+ * This function takes no arguments.
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_filters_dump(void)
+{
+ struct flt_conf *fconf;
+ struct proxy *px;
+
+ FLT_OT_FUNC("");
+
+ for (px = proxies_list; px != NULL; px = px->next) {
+ FLT_OT_DBG(2, "proxy '%s'", px->id);
+
+ list_for_each_entry(fconf, &(px->filter_configs), list)
+ if (fconf->id == ot_flt_id) {
+ struct flt_ot_conf *conf = fconf->conf;
+
+ FLT_OT_DBG(2, " OT filter '%s'", conf->id);
+ }
+ }
+
+ FLT_OT_RETURN();
+}
+
+
+/***
+ * NAME
+ * flt_ot_chn_label -
+ *
+ * ARGUMENTS
+ * chn -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *flt_ot_chn_label(const struct channel *chn)
+{
+ return (chn->flags & CF_ISRESP) ? "RESponse" : "REQuest";
+}
+
+
+/***
+ * NAME
+ * flt_ot_pr_mode -
+ *
+ * ARGUMENTS
+ * s -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *flt_ot_pr_mode(const struct stream *s)
+{
+ struct proxy *px = (s->flags & SF_BE_ASSIGNED) ? s->be : strm_fe(s);
+
+ return (px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP";
+}
+
+
+/***
+ * NAME
+ * flt_ot_stream_pos -
+ *
+ * ARGUMENTS
+ * s -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *flt_ot_stream_pos(const struct stream *s)
+{
+ return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
+}
+
+
+/***
+ * NAME
+ * flt_ot_type -
+ *
+ * ARGUMENTS
+ * f -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *flt_ot_type(const struct filter *f)
+{
+ return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
+}
+
+
+/***
+ * NAME
+ * flt_ot_analyzer -
+ *
+ * ARGUMENTS
+ * an_bit -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *flt_ot_analyzer(uint an_bit)
+{
+#define FLT_OT_AN_DEF(a) { a, #a },
+ static const struct {
+ uint an_bit;
+ const char *str;
+ } flt_ot_an[] = { FLT_OT_AN_DEFINES };
+#undef FLT_OT_AN_DEF
+ const char *retptr = "invalid an_bit";
+ int i;
+
+ for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_an); i++)
+ if (flt_ot_an[i].an_bit == an_bit) {
+ retptr = flt_ot_an[i].str;
+
+ break;
+ }
+
+ return retptr;
+}
+
+
+/***
+ * NAME
+ * flt_ot_str_hex -
+ *
+ * ARGUMENTS
+ * data -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *flt_ot_str_hex(const void *data, size_t size)
+{
+ static THREAD_LOCAL char retbuf[BUFSIZ];
+ const uint8_t *ptr = data;
+ size_t i;
+
+ if (data == NULL)
+ return "(null)";
+ else if (size == 0)
+ return "()";
+
+ for (i = 0, size <<= 1; (i < (sizeof(retbuf) - 2)) && (i < size); ptr++) {
+ retbuf[i++] = FLT_OT_NIBBLE_TO_HEX(*ptr >> 4);
+ retbuf[i++] = FLT_OT_NIBBLE_TO_HEX(*ptr & 0x0f);
+ }
+
+ retbuf[i] = '\0';
+
+ return retbuf;
+}
+
+
+/***
+ * NAME
+ * flt_ot_str_ctrl -
+ *
+ * ARGUMENTS
+ * data -
+ * size -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *flt_ot_str_ctrl(const void *data, size_t size)
+{
+ static THREAD_LOCAL char retbuf[BUFSIZ];
+ const uint8_t *ptr = data;
+ size_t i, n = 0;
+
+ if (data == NULL)
+ return "(null)";
+ else if (size == 0)
+ return "()";
+
+ for (i = 0; (n < (sizeof(retbuf) - 1)) && (i < size); i++)
+ retbuf[n++] = ((ptr[i] >= 0x20) && (ptr[i] <= 0x7e)) ? ptr[i] : '.';
+
+ retbuf[n] = '\0';
+
+ return retbuf;
+}
+
+
+/***
+ * NAME
+ * flt_ot_list_debug -
+ *
+ * ARGUMENTS
+ * head -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+const char *flt_ot_list_debug(const struct list *head)
+{
+ FLT_OT_BUFFER_THR(retbuf, 4, 64, retptr);
+
+ if ((head == NULL) || LIST_ISEMPTY(head)) {
+ (void)strncpy(retptr, (head == NULL) ? "{ null list }" : "{ empty list }", sizeof(retbuf[0]));
+ }
+ else if (head->p == head->n) {
+ (void)snprintf(retptr, sizeof(retbuf[0]), "{ %p * 1 }", head->p);
+ }
+ else {
+ const struct list *ptr;
+ size_t count = 0;
+
+ for (ptr = head->n; ptr != head; ptr = ptr->n, count++);
+
+ (void)snprintf(retptr, sizeof(retbuf[0]), "{ %p %p %zu }", head->p, head->n, count);
+ }
+
+ return (retptr);
+}
+
+#endif /* DEBUG_OT */
+
+
+/***
+ * NAME
+ * flt_ot_chunk_add -
+ *
+ * ARGUMENTS
+ * chk -
+ * src -
+ * n -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+ssize_t flt_ot_chunk_add(struct buffer *chk, const void *src, size_t n, char **err)
+{
+ FLT_OT_FUNC("%p, %p, %zu, %p:%p", chk, src, n, FLT_OT_DPTR_ARGS(err));
+
+ if ((chk == NULL) || (src == NULL))
+ FLT_OT_RETURN_EX(-1, ssize_t, "%ld");
+
+ if (chk->area == NULL)
+ chunk_init(chk, FLT_OT_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
+
+ if (chk->area == NULL) {
+ FLT_OT_ERR("out of memory");
+
+ FLT_OT_RETURN_EX(-1, ssize_t, "%ld");
+ }
+ else if (n > (chk->size - chk->data)) {
+ FLT_OT_ERR("chunk size too small");
+
+ FLT_OT_RETURN_EX(-1, ssize_t, "%ld");
+ }
+
+ (void)memcpy(chk->area + chk->data, src, n);
+ chk->data += n;
+
+ FLT_OT_RETURN_EX(chk->data, ssize_t, "%ld");
+}
+
+
+/***
+ * NAME
+ * flt_ot_args_count -
+ *
+ * ARGUMENTS
+ * args -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int flt_ot_args_count(char **args)
+{
+ int i, retval = 0;
+
+ if (args == NULL)
+ return retval;
+
+ /*
+ * It is possible that some arguments within the configuration line
+ * are not specified; that is, they are set to a blank string.
+ *
+ * For example:
+ * keyword '' arg_2
+ *
+ * In that case the content of the args field will be like this:
+ * args[0]: 'keyword'
+ * args[1]: NULL pointer
+ * args[2]: 'arg_2'
+ * args[3 .. MAX_LINE_ARGS): NULL pointers
+ *
+ * The total number of arguments is the index of the last argument
+ * (increased by 1) that is not a NULL pointer.
+ */
+ for (i = 0; i < MAX_LINE_ARGS; i++)
+ if (FLT_OT_ARG_ISVALID(i))
+ retval = i + 1;
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * flt_ot_args_to_str -
+ *
+ * ARGUMENTS
+ * args -
+ * idx -
+ * str -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_args_to_str(char **args, int idx, char **str)
+{
+ int i, argc;
+
+ if ((args == NULL) || (*args == NULL))
+ return;
+
+ argc = flt_ot_args_count(args);
+
+ for (i = idx; i < argc; i++)
+ (void)memprintf(str, "%s%s%s", (*str == NULL) ? "" : *str, (i == idx) ? "" : " ", (args[i] == NULL) ? "" : args[i]);
+}
+
+
+/***
+ * NAME
+ * flt_ot_strtod -
+ *
+ * ARGUMENTS
+ * nptr -
+ * limit_min -
+ * limit_max -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+double flt_ot_strtod(const char *nptr, double limit_min, double limit_max, char **err)
+{
+ char *endptr = NULL;
+ double retval;
+
+ errno = 0;
+
+ retval = strtod(nptr, &endptr);
+ if ((errno != 0) || FLT_OT_STR_ISVALID(endptr))
+ FLT_OT_ERR("'%s' : invalid value", nptr);
+ else if (!FLT_OT_IN_RANGE(retval, limit_min, limit_max))
+ FLT_OT_ERR("'%s' : value out of range [%.2f, %.2f]", nptr, limit_min, limit_max);
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * flt_ot_strtoll -
+ *
+ * ARGUMENTS
+ * nptr -
+ * limit_min -
+ * limit_max -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int64_t flt_ot_strtoll(const char *nptr, int64_t limit_min, int64_t limit_max, char **err)
+{
+ char *endptr = NULL;
+ int64_t retval;
+
+ errno = 0;
+
+ retval = strtoll(nptr, &endptr, 0);
+ if ((errno != 0) || FLT_OT_STR_ISVALID(endptr))
+ FLT_OT_ERR("'%s' : invalid value", nptr);
+ else if (!FLT_OT_IN_RANGE(retval, limit_min, limit_max))
+ FLT_OT_ERR("'%s' : value out of range [%" PRId64 ", %" PRId64 "]", nptr, limit_min, limit_max);
+
+ return retval;
+}
+
+
+/***
+ * NAME
+ * flt_ot_sample_to_str -
+ *
+ * ARGUMENTS
+ * data -
+ * value -
+ * size -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int flt_ot_sample_to_str(const struct sample_data *data, char *value, size_t size, char **err)
+{
+ int retval = -1;
+
+ FLT_OT_FUNC("%p, %p, %zu, %p:%p", data, value, size, FLT_OT_DPTR_ARGS(err));
+
+ if ((data == NULL) || (value == NULL) || (size == 0))
+ FLT_OT_RETURN_INT(retval);
+
+ *value = '\0';
+
+ if (data->type == SMP_T_ANY) {
+ FLT_OT_ERR("invalid sample data type %d", data->type);
+ }
+ else if (data->type == SMP_T_BOOL) {
+ value[0] = data->u.sint ? '1' : '0';
+ value[1] = '\0';
+
+ retval = 1;
+ }
+ else if (data->type == SMP_T_SINT) {
+ retval = snprintf(value, size, "%lld", data->u.sint);
+ }
+ else if (data->type == SMP_T_ADDR) {
+ /* This type is never used to qualify a sample. */
+ }
+ else if (data->type == SMP_T_IPV4) {
+ if (INET_ADDRSTRLEN > size)
+ FLT_OT_ERR("sample data size too large");
+ else if (inet_ntop(AF_INET, &(data->u.ipv4), value, INET_ADDRSTRLEN) == NULL)
+ FLT_OT_ERR("invalid IPv4 address");
+ else
+ retval = strlen(value);
+ }
+ else if (data->type == SMP_T_IPV6) {
+ if (INET6_ADDRSTRLEN > size)
+ FLT_OT_ERR("sample data size too large");
+ else if (inet_ntop(AF_INET6, &(data->u.ipv6), value, INET6_ADDRSTRLEN) == NULL)
+ FLT_OT_ERR("invalid IPv6 address");
+ else
+ retval = strlen(value);
+ }
+ else if (data->type == SMP_T_STR) {
+ if (data->u.str.data >= size) {
+ FLT_OT_ERR("sample data size too large");
+ }
+ else if (data->u.str.data > 0) {
+ retval = data->u.str.data;
+ memcpy(value, data->u.str.area, retval);
+ value[retval] = '\0';
+ }
+ else {
+ /*
+ * There is no content to add but we will still return
+ * the correct status.
+ */
+ retval = 0;
+ }
+ }
+ else if (data->type == SMP_T_BIN) {
+ FLT_OT_ERR("invalid sample data type %d", data->type);
+ }
+ else if (data->type != SMP_T_METH) {
+ FLT_OT_ERR("invalid sample data type %d", data->type);
+ }
+ else if (data->u.meth.meth == HTTP_METH_OPTIONS) {
+ retval = FLT_OT_STR_SIZE(HTTP_METH_STR_OPTIONS);
+
+ (void)memcpy(value, HTTP_METH_STR_OPTIONS, retval + 1);
+ }
+ else if (data->u.meth.meth == HTTP_METH_GET) {
+ retval = FLT_OT_STR_SIZE(HTTP_METH_STR_GET);
+
+ (void)memcpy(value, HTTP_METH_STR_GET, retval + 1);
+ }
+ else if (data->u.meth.meth == HTTP_METH_HEAD) {
+ retval = FLT_OT_STR_SIZE(HTTP_METH_STR_HEAD);
+
+ (void)memcpy(value, HTTP_METH_STR_HEAD, retval + 1);
+ }
+ else if (data->u.meth.meth == HTTP_METH_POST) {
+ retval = FLT_OT_STR_SIZE(HTTP_METH_STR_POST);
+
+ (void)memcpy(value, HTTP_METH_STR_POST, retval + 1);
+ }
+ else if (data->u.meth.meth == HTTP_METH_PUT) {
+ retval = FLT_OT_STR_SIZE(HTTP_METH_STR_PUT);
+
+ (void)memcpy(value, HTTP_METH_STR_PUT, retval + 1);
+ }
+ else if (data->u.meth.meth == HTTP_METH_DELETE) {
+ retval = FLT_OT_STR_SIZE(HTTP_METH_STR_DELETE);
+
+ (void)memcpy(value, HTTP_METH_STR_DELETE, retval + 1);
+ }
+ else if (data->u.meth.meth == HTTP_METH_TRACE) {
+ retval = FLT_OT_STR_SIZE(HTTP_METH_STR_TRACE);
+
+ (void)memcpy(value, HTTP_METH_STR_TRACE, retval + 1);
+ }
+ else if (data->u.meth.meth == HTTP_METH_CONNECT) {
+ retval = FLT_OT_STR_SIZE(HTTP_METH_STR_CONNECT);
+
+ (void)memcpy(value, HTTP_METH_STR_CONNECT, retval + 1);
+ }
+ else if (data->u.meth.meth == HTTP_METH_OTHER) {
+ if (data->u.meth.str.data >= size) {
+ FLT_OT_ERR("sample data size too large");
+ } else {
+ retval = data->u.meth.str.data;
+ memcpy(value, data->u.meth.str.area, retval);
+ value[retval] = '\0';
+ }
+ }
+ else {
+ FLT_OT_ERR("invalid HTTP method");
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_sample_to_value -
+ *
+ * ARGUMENTS
+ * key -
+ * data -
+ * value -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int flt_ot_sample_to_value(const char *key, const struct sample_data *data, struct otc_value *value, char **err)
+{
+ int retval = -1;
+
+ FLT_OT_FUNC("\"%s\", %p, %p, %p:%p", key, data, value, FLT_OT_DPTR_ARGS(err));
+
+ if ((data == NULL) || (value == NULL))
+ FLT_OT_RETURN_INT(retval);
+
+ if (data->type == SMP_T_BOOL) {
+ value->type = otc_value_bool;
+ value->value.bool_value = data->u.sint ? 1 : 0;
+
+ retval = sizeof(value->value.bool_value);
+ }
+ else if (data->type == SMP_T_SINT) {
+ value->type = otc_value_int64;
+ value->value.int64_value = data->u.sint;
+
+ retval = sizeof(value->value.int64_value);
+ }
+ else {
+ value->type = otc_value_string;
+ value->value.string_value = FLT_OT_MALLOC(global.tune.bufsize);
+
+ if (value->value.string_value == NULL)
+ FLT_OT_ERR("out of memory");
+ else
+ retval = flt_ot_sample_to_str(data, (char *)value->value.string_value, global.tune.bufsize, err);
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_sample_add -
+ *
+ * ARGUMENTS
+ * s -
+ * dir -
+ * sample -
+ * data -
+ * type -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * Returns a negative value if an error occurs, 0 if it needs to wait,
+ * any other value otherwise.
+ */
+int flt_ot_sample_add(struct stream *s, uint dir, struct flt_ot_conf_sample *sample, struct flt_ot_scope_data *data, int type, char **err)
+{
+ const struct flt_ot_conf_sample_expr *expr;
+ struct sample smp;
+ struct otc_value value;
+ struct buffer buffer;
+ int idx = 0, rc, retval = FLT_OT_RET_OK;
+
+ FLT_OT_FUNC("%p, %u, %p, %p, %d, %p:%p", s, dir, data, sample, type, FLT_OT_DPTR_ARGS(err));
+
+ FLT_OT_DBG_CONF_SAMPLE("sample ", sample);
+
+ (void)memset(&buffer, 0, sizeof(buffer));
+
+ list_for_each_entry(expr, &(sample->exprs), list) {
+ FLT_OT_DBG_CONF_SAMPLE_EXPR("sample expression ", expr);
+
+ (void)memset(&smp, 0, sizeof(smp));
+
+ /*
+ * If we have only one expression to process, then the data
+ * type that is the result of the expression is converted to
+ * an equivalent data type (if possible) that is written to
+ * the tracer.
+ *
+ * If conversion is not possible, or if we have multiple
+ * expressions to process, then the result is converted to
+ * a string and as such sent to the tracer.
+ */
+ if (sample_process(s->be, s->sess, s, dir | SMP_OPT_FINAL, expr->expr, &smp) != NULL) {
+ FLT_OT_DBG(3, "data type %d: '%s'", smp.data.type, expr->value);
+ } else {
+ FLT_OT_DBG(2, "WARNING: failed to fetch '%s' value", expr->value);
+
+ /*
+ * In case the fetch failed, we will set the result
+ * (sample) to an empty static string.
+ */
+ (void)memset(&(smp.data), 0, sizeof(smp.data));
+ smp.data.type = SMP_T_STR;
+ smp.data.u.str.area = "";
+ }
+
+ if ((sample->num_exprs == 1) && (type == FLT_OT_EVENT_SAMPLE_TAG)) {
+ if (flt_ot_sample_to_value(sample->key, &(smp.data), &value, err) == -1)
+ retval = FLT_OT_RET_ERROR;
+ } else {
+ if (buffer.area == NULL) {
+ chunk_init(&buffer, FLT_OT_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
+ if (buffer.area == NULL) {
+ FLT_OT_ERR("out of memory");
+
+ retval = FLT_OT_RET_ERROR;
+
+ break;
+ }
+ }
+
+ rc = flt_ot_sample_to_str(&(smp.data), buffer.area + buffer.data, buffer.size - buffer.data, err);
+ if (rc == -1) {
+ retval = FLT_OT_RET_ERROR;
+ } else {
+ buffer.data += rc;
+
+ if (sample->num_exprs == ++idx) {
+ value.type = otc_value_string;
+ value.value.string_value = buffer.area;
+ }
+ }
+ }
+ }
+
+ if (retval == FLT_OT_RET_ERROR) {
+ /* Do nothing. */
+ }
+ else if (type == FLT_OT_EVENT_SAMPLE_TAG) {
+ struct otc_tag *tag = data->tags + data->num_tags++;
+
+ tag->key = sample->key;
+ (void)memcpy(&(tag->value), &value, sizeof(tag->value));
+ }
+ else if (type == FLT_OT_EVENT_SAMPLE_LOG) {
+ struct otc_log_field *log_field = data->log_fields + data->num_log_fields++;
+
+ log_field->key = sample->key;
+ (void)memcpy(&(log_field->value), &value, sizeof(log_field->value));
+ }
+ else {
+ if (data->baggage == NULL)
+ data->baggage = otc_text_map_new(NULL, FLT_OT_MAXBAGGAGES);
+
+ if (data->baggage == NULL) {
+ FLT_OT_ERR("out of memory");
+
+ retval = FLT_OT_RET_ERROR;
+ }
+ else if (otc_text_map_add(data->baggage, sample->key, 0, value.value.string_value, 0, 0) == -1) {
+ FLT_OT_ERR("out of memory");
+
+ retval = FLT_OT_RET_ERROR;
+ }
+ else
+ FLT_OT_DBG(3, "baggage[%zu]: '%s' -> '%s'", data->baggage->count - 1, data->baggage->key[data->baggage->count - 1], data->baggage->value[data->baggage->count - 1]);
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */
diff --git a/addons/ot/src/vars.c b/addons/ot/src/vars.c
new file mode 100644
index 0000000..e99bab1
--- /dev/null
+++ b/addons/ot/src/vars.c
@@ -0,0 +1,834 @@
+/***
+ * Copyright 2020 HAProxy Technologies
+ *
+ * This file is part of the HAProxy OpenTracing filter.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "include.h"
+
+
+#ifdef DEBUG_OT
+
+/***
+ * NAME
+ * flt_ot_vars_scope_dump -
+ *
+ * ARGUMENTS
+ * vars -
+ * scope -
+ *
+ * DESCRIPTION
+ * Function prints the contents of all variables defined for a particular
+ * scope.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static void flt_ot_vars_scope_dump(struct vars *vars, const char *scope)
+{
+ const struct var *var;
+
+ if (vars == NULL)
+ return;
+
+ vars_rdlock(vars);
+ list_for_each_entry(var, &(vars->head), l)
+ 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);
+}
+
+
+/***
+ * NAME
+ * flt_ot_vars_dump -
+ *
+ * ARGUMENTS
+ * s -
+ *
+ * DESCRIPTION
+ * Function prints the contents of all variables grouped by individual
+ * scope.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+void flt_ot_vars_dump(struct stream *s)
+{
+ FLT_OT_FUNC("%p", s);
+
+ /*
+ * It would be nice if we could use the get_vars() function from HAProxy
+ * source here to get the value of the 'vars' pointer, but it is defined
+ * as 'static inline', so unfortunately none of this is possible.
+ */
+ flt_ot_vars_scope_dump(&(proc_vars), "PROC");
+ flt_ot_vars_scope_dump(&(s->sess->vars), "SESS");
+ flt_ot_vars_scope_dump(&(s->vars_txn), "TXN");
+ flt_ot_vars_scope_dump(&(s->vars_reqres), "REQ/RES");
+
+ FLT_OT_RETURN();
+}
+
+#endif /* DEBUG_OT */
+
+
+/***
+ * NAME
+ * flt_ot_smp_init -
+ *
+ * ARGUMENTS
+ * s -
+ * smp -
+ * opt -
+ * type -
+ * data -
+ *
+ * DESCRIPTION
+ * The function initializes the value of the 'smp' structure. If the 'data'
+ * argument is set, then the 'sample_data' member of the 'smp' structure is
+ * also initialized.
+ *
+ * RETURN VALUE
+ * This function does not return a value.
+ */
+static inline void flt_ot_smp_init(struct stream *s, struct sample *smp, uint opt, int type, const char *data)
+{
+ (void)memset(smp, 0, sizeof(*smp));
+ (void)smp_set_owner(smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
+
+ if (data != NULL) {
+ smp->data.type = type;
+
+ chunk_initstr(&(smp->data.u.str), data);
+ }
+}
+
+
+/***
+ * NAME
+ * flt_ot_smp_add -
+ *
+ * ARGUMENTS
+ * data -
+ * blk -
+ * len -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_smp_add(struct sample_data *data, const char *name, size_t len, char **err)
+{
+ bool flag_alloc = 0;
+ int retval = FLT_OT_RET_ERROR;
+
+ FLT_OT_FUNC("%p, \"%.*s\", %zu, %p:%p", data, (int)len, name, len, FLT_OT_DPTR_ARGS(err));
+
+ 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);
+}
+
+
+/***
+ * NAME
+ * flt_ot_normalize_name -
+ *
+ * ARGUMENTS
+ * var_name -
+ * size -
+ * len -
+ * name -
+ * flag_cpy -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_normalize_name(char *var_name, size_t size, int *len, const char *name, bool flag_cpy, char **err)
+{
+ int retval = 0;
+
+ FLT_OT_FUNC("%p, %zu, %p, \"%s\", %hhu, %p:%p", var_name, size, len, name, flag_cpy, FLT_OT_DPTR_ARGS(err));
+
+ if (!FLT_OT_STR_ISVALID(name))
+ FLT_OT_RETURN_INT(retval);
+
+ /*
+ * In case the name of the variable consists of several elements,
+ * the character '.' is added between them.
+ */
+ if ((*len == 0) || (var_name[*len - 1] == '.'))
+ /* Do nothing. */;
+ else if (*len < (size - 1))
+ var_name[(*len)++] = '.';
+ 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");
+
+ retval = -1;
+ } else {
+ (void)memcpy(var_name + *len, name, retval + 1);
+
+ *len += retval;
+ }
+ } else {
+ /*
+ * HAProxy does not allow the use of variable names containing '-'
+ * or ' '. This of course applies to HTTP header names as well.
+ * Also, here the capital letters are converted to lowercase.
+ */
+ while (retval != -1)
+ if (*len >= (size - 1)) {
+ FLT_OT_ERR("failed to normalize variable name, buffer too small");
+
+ retval = -1;
+ } else {
+ uint8_t ch = name[retval];
+
+ if (ch == '\0')
+ break;
+ else if (ch == '-')
+ ch = FLT_OT_VAR_CHAR_DASH;
+ else if (ch == ' ')
+ ch = FLT_OT_VAR_CHAR_SPACE;
+ else if (isupper(ch))
+ ch = ist_lc[ch];
+
+ var_name[(*len)++] = ch;
+ retval++;
+ }
+
+ var_name[*len] = '\0';
+ }
+
+ FLT_OT_DBG(3, "var_name: \"%s\" %d/%d", var_name, retval, *len);
+
+ if (retval == -1)
+ *len = retval;
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_var_name -
+ *
+ * ARGUMENTS
+ * scope -
+ * prefix -
+ * name -
+ * flag_cpy -
+ * var_name -
+ * size -
+ * err -
+ *
+ * DESCRIPTION
+ * The function initializes the value of the 'smp' structure. If the 'data'
+ * argument is set, then the 'sample_data' member of the 'smp' structure is
+ * also initialized.
+ *
+ * RETURN VALUE
+ * -
+ */
+static int flt_ot_var_name(const char *scope, const char *prefix, const char *name, bool flag_cpy, char *var_name, size_t size, char **err)
+{
+ int retval = 0;
+
+ FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %hhu, %p, %zu, %p:%p", scope, prefix, name, flag_cpy, var_name, size, FLT_OT_DPTR_ARGS(err));
+
+ if (flt_ot_normalize_name(var_name, size, &retval, scope, 0, err) >= 0)
+ if (flt_ot_normalize_name(var_name, size, &retval, prefix, 0, err) >= 0)
+ (void)flt_ot_normalize_name(var_name, size, &retval, name, flag_cpy, err);
+
+ if (retval == -1)
+ FLT_OT_ERR("failed to construct variable name '%s.%s.%s'", scope, prefix, name);
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * 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 -
+ *
+ * ARGUMENTS
+ * scope -
+ * prefix -
+ * name -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int flt_ot_var_register(const char *scope, const char *prefix, const char *name, char **err)
+{
+ struct arg arg;
+ char var_name[BUFSIZ];
+ int retval = -1, var_name_len;
+
+ FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p:%p", scope, prefix, name, FLT_OT_DPTR_ARGS(err));
+
+ var_name_len = flt_ot_var_name(scope, prefix, name, 0, var_name, sizeof(var_name), err);
+ if (var_name_len == -1)
+ FLT_OT_RETURN_INT(retval);
+
+ /* Set <size> to 0 to not release var_name memory in vars_check_arg(). */
+ (void)memset(&arg, 0, sizeof(arg));
+ arg.type = ARGT_STR;
+ arg.data.str.area = var_name;
+ arg.data.str.data = var_name_len;
+
+ 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", var_name);
+
+ retval = var_name_len;
+ }
+
+ FLT_OT_RETURN_INT(retval);
+}
+
+
+/***
+ * NAME
+ * flt_ot_var_set -
+ *
+ * ARGUMENTS
+ * s -
+ * scope -
+ * prefix -
+ * name -
+ * value -
+ * opt -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int flt_ot_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err)
+{
+ struct sample smp;
+ char var_name[BUFSIZ];
+ int retval = -1, var_name_len;
+
+ FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, value, opt, FLT_OT_DPTR_ARGS(err));
+
+ var_name_len = flt_ot_var_name(scope, prefix, name, 0, var_name, sizeof(var_name), err);
+ if (var_name_len == -1)
+ FLT_OT_RETURN_INT(retval);
+
+ flt_ot_smp_init(s, &smp, opt, SMP_T_STR, value);
+
+ if (vars_set_by_name_ifexist(var_name, var_name_len, &smp) == 0) {
+ FLT_OT_ERR("failed to set variable '%s'", var_name);
+ } else {
+ 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);
+}
+
+
+/***
+ * NAME
+ * flt_ot_vars_unset -
+ *
+ * ARGUMENTS
+ * s -
+ * scope -
+ * prefix -
+ * opt -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+int flt_ot_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
+{
+ 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));
+
+ flt_ot_smp_init(s, &smp_ctx, opt, 0, NULL);
+
+ 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);
+
+ flt_ot_smp_init(s, &smp_ctx, opt, 0, NULL);
+
+ 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);
+
+ retval = 1;
+ }
+ }
+
+ 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);
+}
+
+
+/***
+ * NAME
+ * flt_ot_vars_get -
+ *
+ * ARGUMENTS
+ * s -
+ * scope -
+ * prefix -
+ * opt -
+ * err -
+ *
+ * DESCRIPTION
+ * -
+ *
+ * RETURN VALUE
+ * -
+ */
+struct otc_text_map *flt_ot_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
+{
+ 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));
+
+ flt_ot_smp_init(s, &smp_ctx, opt, 0, NULL);
+
+ (void)flt_ot_ctx_loop(&smp_ctx, scope, prefix, err, flt_ot_vars_get_cb, &retptr);
+
+ ot_text_map_show(retptr);
+
+ if ((retptr != NULL) && (retptr->count == 0)) {
+ FLT_OT_DBG(2, "WARNING: no variables found");
+
+ otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
+ }
+
+ FLT_OT_RETURN_PTR(retptr);
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * End:
+ *
+ * vi: noexpandtab shiftwidth=8 tabstop=8
+ */