| /*** |
| * 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(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(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(++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(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(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(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(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(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(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); |
| |
| flt_ot_vars_dump(s); |
| flt_ot_http_headers_dump(&(s->req)); |
| |
| FLT_OT_RETURN(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(retval); |
| |
| FLT_OT_RETURN(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(retval); |
| |
| FLT_OT_DBG(3, "backend: %s", be->id); |
| |
| FLT_OT_RETURN(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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 |
| */ |