From: Arran Cudbard-Bell Date: Sat, 31 May 2025 19:25:12 +0000 (-0600) Subject: Add better support for async maps X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6280fe7b423d525bf23df2b79cbfc6fae93f36aa;p=thirdparty%2Ffreeradius-server.git Add better support for async maps We really don't want to push additional frames if we can help it --- diff --git a/src/bin/unit_test_module.c b/src/bin/unit_test_module.c index ca717950450..1725568e5c8 100644 --- a/src/bin/unit_test_module.c +++ b/src/bin/unit_test_module.c @@ -592,11 +592,11 @@ static int map_proc_verify(CONF_SECTION *cs, UNUSED void const *mod_inst, UNUSED return 0; } -static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void const *mod_inst, UNUSED void *proc_inst, +static unlang_action_t mod_map_proc(unlang_result_t *p_result, UNUSED map_ctx_t const *mpctx, UNUSED request_t *request, UNUSED fr_value_box_list_t *src, UNUSED map_list_t const *maps) { - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } static request_t *request_clone(request_t *old, int number, CONF_SECTION *server_cs) diff --git a/src/lib/server/map_proc.c b/src/lib/server/map_proc.c index 4d4034b4845..2826ce6758e 100644 --- a/src/lib/server/map_proc.c +++ b/src/lib/server/map_proc.c @@ -225,20 +225,3 @@ map_proc_inst_t *map_proc_instantiate(TALLOC_CTX *ctx, map_proc_t const *proc, return inst; } - -/** Evaluate a set of maps using the specified map processor - * - * Evaluate the map processor src template, then call a map processor function to do - * something with the expanded src template and map the result to attributes in the request. - * - * @param[out] p_result Result code of evaluating the map. - * @param[in] request The current request. - * @param[in] inst of a map processor. - * @param[in,out] result Result of expanding the map input. May be consumed - * by the map processor. - * @return one of UNLANG_ACTION_* - */ -unlang_action_t map_proc(rlm_rcode_t *p_result, request_t *request, map_proc_inst_t const *inst, fr_value_box_list_t *result) -{ - return inst->proc->evaluate(p_result, inst->proc->mod_inst, inst->data, request, result, inst->maps); -} diff --git a/src/lib/server/map_proc.h b/src/lib/server/map_proc.h index 9a83cda7654..08832c95f57 100644 --- a/src/lib/server/map_proc.h +++ b/src/lib/server/map_proc.h @@ -46,21 +46,29 @@ typedef struct map_proc_inst map_proc_inst_t; extern "C" { #endif +/** Temporary structure to hold arguments for map calls + * + */ +typedef struct { + void *rctx; //!< Resume ctx that a module previously set. + void const *moi; //!< Map module instance. + void const *mpi; //!< Map processor instance. +} map_ctx_t; + /** Function to evaluate the src string and map the result to server attributes * * @param[out] p_result Result of applying the map: * - #RLM_MODULE_NOOP - If no data available for given src, or no mappings matched available data. * - #RLM_MODULE_UPDATED - If new pairs were added to the request. * - #RLM_MODULE_FAIL - If an error occurred performing the mapping. - * @param[in] mod_inst Instance of the module that registered the map_proc. - * @param[in] proc_inst Map proc data created by #map_proc_instantiate_t. + * @param[in] mpctx Call ctx for the map processor. * @param[in] request The current request. * @param[in,out] result Input data for the map processor. May be consumed by the * map processor. * @param[in] maps Head of the list of maps to process. * @return one of UNLANG_ACTION_* */ -typedef unlang_action_t (*map_proc_func_t)(rlm_rcode_t *p_result, void const *mod_inst, void *proc_inst, request_t *request, +typedef unlang_action_t (*map_proc_func_t)(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request, fr_value_box_list_t *result, map_list_t const *maps); /** Allocate new instance data for a map processor @@ -89,9 +97,6 @@ int map_proc_unregister(char const *name); map_proc_inst_t *map_proc_instantiate(TALLOC_CTX *ctx, map_proc_t const *proc, CONF_SECTION *cs, tmpl_t const *src, map_list_t const *maps); - -unlang_action_t map_proc(rlm_rcode_t *p_result, request_t *request, map_proc_inst_t const *inst, fr_value_box_list_t *src); - #ifdef __cplusplus } #endif diff --git a/src/lib/unlang/map.c b/src/lib/unlang/map.c index 7871a111050..8ccab42c2be 100644 --- a/src/lib/unlang/map.c +++ b/src/lib/unlang/map.c @@ -28,8 +28,9 @@ RCSID("$Id$") #include +#include #include - +#include #include "map_priv.h" @@ -43,23 +44,41 @@ typedef enum { * */ typedef struct { - fr_dcursor_t maps; //!< Cursor of maps to evaluate. + fr_dcursor_t maps; //!< Cursor of maps to evaluate. - fr_dlist_head_t vlm_head; //!< Head of list of VP List Mod. + fr_dlist_head_t vlm_head; //!< Head of list of VP List Mod. - fr_value_box_list_t lhs_result; //!< Result of expanding the LHS - fr_value_box_list_t rhs_result; //!< Result of expanding the RHS. + fr_value_box_list_t lhs_result; //!< Result of expanding the LHS + fr_value_box_list_t rhs_result; //!< Result of expanding the RHS. - unlang_update_state_t state; //!< What we're currently doing. + unlang_update_state_t state; //!< What we're currently doing. } unlang_frame_state_update_t; /** State of a map block * */ typedef struct { - fr_value_box_list_t src_result; //!< Result of expanding the map source. + fr_value_box_list_t src_result; //!< Result of expanding the map source. + + /** @name Resumption and signalling + * @{ + */ + void *rctx; //!< for resume / signal + map_proc_func_t resume; //!< resumption handler + unlang_map_signal_t signal; //!< for signal handlers + fr_signal_t sigmask; //!< Signals to block. + + /** @} */ } unlang_frame_state_map_proc_t; +/** Wrapper to create a map_ctx_t as a compound literal + * + * @param[in] _mod_inst of the module being called. + * @param[in] _map_inst of the map being called. + * @param[in] _rctx Resume ctx (if any). + */ +#define MAP_CTX(_mod_inst, _map_inst, _rctx) &(map_ctx_t){ .moi = _mod_inst, .mpi = _map_inst, .rctx = _rctx } + /** Apply a list of modifications on one or more fr_pair_t lists. * * @param[in] request The current request. @@ -274,7 +293,7 @@ static unlang_action_t unlang_update_state_init(unlang_result_t *p_result, reque return list_mod_create(p_result, request, frame); } -static unlang_action_t map_proc_resume(UNUSED unlang_result_t *p_result, UNUSED request_t *request, +static unlang_action_t map_proc_resume(unlang_result_t *p_result, request_t *request, #ifdef WITH_VERIFY_PTR unlang_stack_frame_t *frame #else @@ -282,11 +301,68 @@ static unlang_action_t map_proc_resume(UNUSED unlang_result_t *p_result, UNUSED #endif ) { -#ifdef WITH_VERIFY_PTR + unlang_frame_state_map_proc_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_map_proc_t); unlang_frame_state_map_proc_t *map_proc_state = talloc_get_type_abort(frame->state, unlang_frame_state_map_proc_t); + map_proc_func_t resume; + unlang_group_t *g = unlang_generic_to_group(frame->instruction); + unlang_map_t *gext = unlang_group_to_map(g); + map_proc_inst_t *inst = gext->proc_inst; + unlang_action_t ua = UNLANG_ACTION_CALCULATE_RESULT; + +#ifdef WITH_VERIFY_PTR VALUE_BOX_LIST_VERIFY(&map_proc_state->src_result); #endif - return UNLANG_ACTION_CALCULATE_RESULT; + resume = state->resume; + state->resume = NULL; + + /* + * Call any map resume function + */ + if (resume) ua = resume(p_result, MAP_CTX(inst->proc->mod_inst, inst->data, state->rctx), + request, &map_proc_state->src_result, inst->maps); + return ua; +} + +/** Yield a request back to the interpreter from within a module + * + * This passes control of the request back to the unlang interpreter, setting + * callbacks to execute when the request is 'signalled' asynchronously, or whatever + * timer or I/O event the module was waiting for occurs. + * + * @note The module function which calls #unlang_module_yield should return control + * of the C stack to the unlang interpreter immediately after calling #unlang_module_yield. + * A common pattern is to use ``return unlang_module_yield(...)``. + * + * @param[in] request The current request. + * @param[in] resume Called on unlang_interpret_mark_runnable(). + * @param[in] signal Called on unlang_action(). + * @param[in] sigmask Set of signals to block. + * @param[in] rctx to pass to the callbacks. + * @return + * - UNLANG_ACTION_YIELD. + */ +unlang_action_t unlang_map_yield(request_t *request, + map_proc_func_t resume, unlang_map_signal_t signal, fr_signal_t sigmask, void *rctx) +{ + unlang_stack_t *stack = request->stack; + unlang_stack_frame_t *frame = &stack->frame[stack->depth]; + unlang_frame_state_map_proc_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_map_proc_t); + + REQUEST_VERIFY(request); /* Check the yielded request is sane */ + + state->rctx = rctx; + state->resume = resume; + state->signal = signal; + state->sigmask = sigmask; + + /* + * We set the repeatable flag here, + * so that the resume function is always + * called going back up the stack. + */ + frame_repeat(frame, map_proc_resume); + + return UNLANG_ACTION_YIELD; } static unlang_action_t map_proc_apply(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame) @@ -301,7 +377,9 @@ static unlang_action_t map_proc_apply(unlang_result_t *p_result, request_t *requ VALUE_BOX_LIST_VERIFY(&map_proc_state->src_result); frame_repeat(frame, map_proc_resume); - return map_proc(&p_result->rcode, request, gext->proc_inst, &map_proc_state->src_result); + + return inst->proc->evaluate(p_result, MAP_CTX(inst->proc->mod_inst, inst->data, NULL), + request, &map_proc_state->src_result, inst->maps); } static unlang_action_t unlang_map_state_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame) diff --git a/src/lib/unlang/map.h b/src/lib/unlang/map.h new file mode 100644 index 00000000000..f44c18ce560 --- /dev/null +++ b/src/lib/unlang/map.h @@ -0,0 +1,49 @@ +#pragma once +/* + * 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, 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. + */ + +/** + * $Id$ + * + * @file unlang/map.h + * + * @copyright 2025 Arran Cudbard-Bell + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include + +/** A callback when the request gets a fr_signal_t. + * + * @note The callback is automatically removed on unlang_interpret_mark_runnable(). + * + * @param[in] mpctx calling context for the map function. + * @param[in] request The current request. + * @param[in] action which is signalling the request. + */ +typedef void (*unlang_map_signal_t)(map_ctx_t const *mpctx, request_t *request, fr_signal_t action); + +unlang_action_t unlang_map_yield(request_t *request, + map_proc_func_t resume, unlang_map_signal_t signal, fr_signal_t sigmask, void *rctx); +#ifdef __cplusplus +} +#endif diff --git a/src/modules/rlm_client/rlm_client.c b/src/modules/rlm_client/rlm_client.c index b0004a75028..4e0a5011e5c 100644 --- a/src/modules/rlm_client/rlm_client.c +++ b/src/modules/rlm_client/rlm_client.c @@ -108,15 +108,14 @@ static int _map_proc_client_get_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request * - #RLM_MODULE_NOOP no rows were returned. * - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t. * - #RLM_MODULE_FAIL if an error occurred. - * @param[in] mod_inst NULL. - * @param[in] proc_inst NULL. + * @param[in] mpctx NULL * @param[in] request The current request. * @param[in] client_override If NULL, use the current client, else use the client matching * the ip given. * @param[in] maps Head of the map list. * @return UNLANG_ACTION_CALCULATE_RESULT */ -static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const *mod_inst, UNUSED void *proc_inst, +static unlang_action_t map_proc_client(unlang_result_t *p_result, UNUSED map_ctx_t const *mpctx, request_t *request, fr_value_box_list_t *client_override, map_list_t const *maps) { rlm_rcode_t rcode = RLM_MODULE_OK; @@ -138,7 +137,7 @@ static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) { REDEBUG("Failed concatenating input data"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } client_str = client_override_head->vb_strvalue; @@ -173,7 +172,7 @@ static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const client = client_from_request(request); if (!client) { REDEBUG("No client associated with this request"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } } uctx.cs = client->cs; @@ -213,7 +212,7 @@ static unlang_action_t map_proc_client(rlm_rcode_t *p_result, UNUSED void const REXDENT(); finish: - RETURN_MODULE_RCODE(rcode); + RETURN_UNLANG_RCODE(rcode); } static xlat_arg_parser_t const xlat_client_args[] = { diff --git a/src/modules/rlm_csv/rlm_csv.c b/src/modules/rlm_csv/rlm_csv.c index aa97808a62f..dea47edc7ed 100644 --- a/src/modules/rlm_csv/rlm_csv.c +++ b/src/modules/rlm_csv/rlm_csv.c @@ -31,7 +31,7 @@ RCSID("$Id$") #include -static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, UNUSED void *proc_inst, request_t *request, +static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request, fr_value_box_list_t *key, map_list_t const *maps); /* @@ -968,22 +968,21 @@ finish: * - #RLM_MODULE_NOOP no rows were returned. * - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t. * - #RLM_MODULE_FAIL if an error occurred. - * @param[in] mod_inst #rlm_csv_t. - * @param[in] proc_inst mapping map entries to field numbers. + * @param[in] mpctx #map_ctx_t, which contains the module and map instances. * @param[in,out] request The current request. * @param[in] key key to look for * @param[in] maps Head of the map list. * @return UNLANG_ACTION_CALCULATE_RESULT */ -static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, UNUSED void *proc_inst, request_t *request, +static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request, fr_value_box_list_t *key, map_list_t const *maps) { - rlm_csv_t const *inst = talloc_get_type_abort_const(mod_inst, rlm_csv_t); + rlm_csv_t const *inst = talloc_get_type_abort_const(mpctx->moi, rlm_csv_t); fr_value_box_t *key_head = fr_value_box_list_head(key); if (!key_head) { REDEBUG("CSV key cannot be (null)"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } if ((inst->key_data_type == FR_TYPE_OCTETS) || (inst->key_data_type == FR_TYPE_STRING)) { @@ -992,11 +991,11 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) { REDEBUG("Failed parsing key"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } } - RETURN_MODULE_RCODE(mod_map_apply(inst, request, key_head, maps)); + RETURN_UNLANG_RCODE(mod_map_apply(inst, request, key_head, maps)); } diff --git a/src/modules/rlm_json/rlm_json.c b/src/modules/rlm_json/rlm_json.c index bd324f98c86..cb1c9f76ea9 100644 --- a/src/modules/rlm_json/rlm_json.c +++ b/src/modules/rlm_json/rlm_json.c @@ -444,20 +444,19 @@ static int _json_map_proc_get_value(TALLOC_CTX *ctx, fr_pair_list_t *out, reques * - #RLM_MODULE_NOOP no rows were returned or columns matched. * - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t. * - #RLM_MODULE_FAIL if a fault occurred. - * @param mod_inst unused. - * @param proc_inst cached jpath sequences. + * @param mpctx Call context for the map processor, containing the jpath cache. * @param request The current request. * @param json JSON string to parse. * @param maps Head of the map list. * @return UNLANG_ACTION_CALCULATE_RESULT */ -static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void const *mod_inst, void *proc_inst, request_t *request, +static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request, fr_value_box_list_t *json, map_list_t const *maps) { rlm_rcode_t rcode = RLM_MODULE_UPDATED; struct json_tokener *tok; - rlm_json_jpath_cache_t *cache = proc_inst; + rlm_json_jpath_cache_t const *cache = mpctx->mpi; map_t const *map = NULL; rlm_json_jpath_to_eval_t to_eval; @@ -467,7 +466,7 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void const *mo if (!json_head) { REDEBUG("JSON map input cannot be (null)"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } if (fr_value_box_list_concat_in_place(request, @@ -475,13 +474,13 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void const *mo FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) { REDEBUG("Failed concatenating input"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } json_str = json_head->vb_strvalue; if ((talloc_array_length(json_str) - 1) == 0) { REDEBUG("JSON map input length must be > 0"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } tok = json_tokener_new(); @@ -548,7 +547,7 @@ finish: json_object_put(to_eval.root); json_tokener_free(tok); - RETURN_MODULE_RCODE(rcode); + RETURN_UNLANG_RCODE(rcode); } static int mod_instantiate(module_inst_ctx_t const *mctx) diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index 9b72f5279cc..4f6df9fe73b 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -1429,17 +1429,16 @@ static int map_ctx_free(ldap_map_ctx_t *map_ctx) * - #RLM_MODULE_NOOP no rows were returned. * - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t. * - #RLM_MODULE_FAIL if an error occurred. - * @param[in] mod_inst #rlm_ldap_t - * @param[in] proc_inst unused. + * @param[in] mpctx module map ctx. * @param[in,out] request The current request. * @param[in] url LDAP url specifying base DN and filter. * @param[in] maps Head of the map list. * @return UNLANG_ACTION_CALCULATE_RESULT */ -static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, UNUSED void *proc_inst, request_t *request, +static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request, fr_value_box_list_t *url, map_list_t const *maps) { - rlm_ldap_t const *inst = talloc_get_type_abort_const(mod_inst, rlm_ldap_t); + rlm_ldap_t const *inst = talloc_get_type_abort_const(mpctx->mpi, rlm_ldap_t); fr_ldap_thread_t *thread = talloc_get_type_abort(module_thread(inst->mi)->data, fr_ldap_thread_t); LDAPURLDesc *ldap_url; @@ -1452,24 +1451,24 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, if (fr_uri_escape_list(url, ldap_uri_parts, NULL) < 0) { RPERROR("Failed to escape LDAP map URI"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } url_head = fr_value_box_list_head(url); if (!url_head) { REDEBUG("LDAP URL cannot be empty"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } if (fr_value_box_list_concat_in_place(url_head, url_head, url, FR_TYPE_STRING, FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) { RPEDEBUG("Failed concatenating input"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } if (!ldap_is_ldap_url(url_head->vb_strvalue)) { REDEBUG("Map query string does not look like a valid LDAP URI"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } MEM(map_ctx = talloc_zero(unlang_interpret_frame_talloc_ctx(request), ldap_map_ctx_t)); @@ -1481,7 +1480,7 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, RPEDEBUG("Parsing LDAP URL failed - %s", fr_ldap_url_err_to_str(ldap_url_ret)); fail: talloc_free(map_ctx); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } ldap_url = map_ctx->ldap_url; diff --git a/src/modules/rlm_sql/rlm_sql.c b/src/modules/rlm_sql/rlm_sql.c index 1f11d61ae8b..8e93a78abff 100644 --- a/src/modules/rlm_sql/rlm_sql.c +++ b/src/modules/rlm_sql/rlm_sql.c @@ -202,15 +202,6 @@ typedef struct { sql_group_ctx_t *group_ctx; //!< Context used for retrieving user group membership. } sql_autz_ctx_t; -/** Context for SQL maps - * - */ -typedef struct { - rlm_sql_t const *inst; - map_list_t const *maps; - fr_sql_query_t *query_ctx; -} sql_map_ctx_t; - typedef struct { fr_value_box_t user; //!< Expansion of sql_user_name. fr_value_box_t filename; //!< File name to write SQL logs to. @@ -716,17 +707,21 @@ static int sql_map_verify(CONF_SECTION *cs, UNUSED void const *mod_inst, UNUSED /** Process the results of an SQL map query * - * @param[out] p_result Result of applying the map. - * @param[in] request Current request. - * @param[in] uctx Map context. - * @return One of UNLANG_ACTION_* + * @param p_result Result of map expansion: + * - #RLM_MODULE_NOOP no rows were returned or columns matched. + * - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t. + * - #RLM_MODULE_FAIL if a fault occurred. + * @param mpctx Map context, containing the module instance. + * @param request The current request. + * @param query string to execute. + * @param maps Head of the map list. + * @return UNLANG_ACTION_CALCULATE_RESULT */ -static unlang_action_t mod_map_resume(unlang_result_t *p_result, request_t *request, void *uctx) +static unlang_action_t mod_map_resume(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request, + UNUSED fr_value_box_list_t *query, map_list_t const *maps) { - sql_map_ctx_t *map_ctx = talloc_get_type_abort(uctx, sql_map_ctx_t); - fr_sql_query_t *query_ctx = map_ctx->query_ctx; - map_list_t const *maps = map_ctx->maps; - rlm_sql_t const *inst = map_ctx->inst; + fr_sql_query_t *query_ctx = talloc_get_type_abort(mpctx->rctx, fr_sql_query_t); + rlm_sql_t const *inst = mpctx->moi; map_t const *map; rlm_rcode_t rcode = RLM_MODULE_UPDATED; sql_rcode_t ret; @@ -843,7 +838,7 @@ static unlang_action_t mod_map_resume(unlang_result_t *p_result, request_t *requ finish: talloc_free(fields); - talloc_free(map_ctx); + talloc_free(query_ctx); RETURN_UNLANG_RCODE(rcode); } @@ -854,20 +849,19 @@ finish: * - #RLM_MODULE_NOOP no rows were returned or columns matched. * - #RLM_MODULE_UPDATED if one or more #fr_pair_t were added to the #request_t. * - #RLM_MODULE_FAIL if a fault occurred. - * @param mod_inst #rlm_sql_t instance. - * @param proc_inst Instance data for this specific mod_proc call (unused). - * @param request The current request. - * @param query string to execute. - * @param maps Head of the map list. + * @param mpctx Map context, containing the module instance. + * @param request The current request. + * @param query string to execute. + * @param maps Head of the map list. * @return UNLANG_ACTION_CALCULATE_RESULT */ -static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, UNUSED void *proc_inst, request_t *request, - fr_value_box_list_t *query, map_list_t const *maps) +static unlang_action_t mod_map_proc(unlang_result_t *p_result, map_ctx_t const *mpctx, request_t *request, + fr_value_box_list_t *query, UNUSED map_list_t const *maps) { - rlm_sql_t const *inst = talloc_get_type_abort_const(mod_inst, rlm_sql_t); + rlm_sql_t const *inst = talloc_get_type_abort_const(mpctx->moi, rlm_sql_t); rlm_sql_thread_t *thread = talloc_get_type_abort(module_thread(inst->mi)->data, rlm_sql_thread_t); fr_value_box_t *query_head = fr_value_box_list_head(query); - sql_map_ctx_t *map_ctx; + fr_sql_query_t *query_ctx = NULL; fr_value_box_t *vb = NULL; rlm_sql_escape_uctx_t *escape_uctx = NULL; @@ -875,7 +869,7 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, if (!query_head) { REDEBUG("Query cannot be (null)"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } while ((vb = fr_value_box_list_next(query, vb))) { @@ -889,22 +883,14 @@ static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, void const *mod_inst, FR_VALUE_BOX_LIST_FREE, true, SIZE_MAX) < 0) { RPEDEBUG("Failed concatenating input string"); - RETURN_MODULE_FAIL; + RETURN_UNLANG_FAIL; } - MEM(map_ctx = talloc(unlang_interpret_frame_talloc_ctx(request), sql_map_ctx_t)); - *map_ctx = (sql_map_ctx_t) { - .inst = inst, - .maps = maps, - }; - - MEM(map_ctx->query_ctx = fr_sql_query_alloc(map_ctx, inst, request, - thread->trunk, query_head->vb_strvalue, SQL_QUERY_SELECT)); - - if (unlang_function_push(NULL, request, NULL, mod_map_resume, NULL, 0, - UNLANG_SUB_FRAME, map_ctx) != UNLANG_ACTION_PUSHED_CHILD) RETURN_MODULE_FAIL; + query_ctx = fr_sql_query_alloc(unlang_interpret_frame_talloc_ctx(request), inst, request, + thread->trunk, query_head->vb_strvalue, SQL_QUERY_SELECT); - return unlang_function_push(NULL, request, inst->select, NULL, NULL, 0, UNLANG_SUB_FRAME, map_ctx->query_ctx); + if (unlang_map_yield(request, mod_map_resume, NULL, 0, query_ctx) != UNLANG_ACTION_YIELD) RETURN_UNLANG_FAIL; + return unlang_function_push(NULL, request, inst->select, NULL, NULL, 0, UNLANG_SUB_FRAME, query_ctx); } /** xlat escape function for drivers which do not provide their own