/*** * 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

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 */