From: Arran Cudbard-Bell Date: Wed, 8 Dec 2021 18:47:10 +0000 (-0500) Subject: reorganise and rename tmpl_cursor functions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=102bec777117e295e97bae8cb5e01f41d2eaa15b;p=thirdparty%2Ffreeradius-server.git reorganise and rename tmpl_cursor functions --- diff --git a/src/lib/server/cond_eval.c b/src/lib/server/cond_eval.c index 443249cf26..26027146d9 100644 --- a/src/lib/server/cond_eval.c +++ b/src/lib/server/cond_eval.c @@ -25,11 +25,12 @@ */ RCSID("$Id$") -#include #include +#include #include #include #include +#include #include #include @@ -522,7 +523,7 @@ static bool cond_compare_attrs(request_t *request, fr_value_box_t *lhs, map_t co int rcode; fr_pair_t *vp; fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; fr_value_box_t *rhs, rhs_cast; fr_dict_attr_t const *da = NULL; @@ -532,7 +533,7 @@ static bool cond_compare_attrs(request_t *request, fr_value_box_t *lhs, map_t co rhs = NULL; /* shut up clang scan */ fr_value_box_init_null(&rhs_cast); - for (vp = tmpl_pair_cursor_init(&rcode, request, &cc, &cursor, request, map->rhs); + for (vp = tmpl_dcursor_init(&rcode, request, &cc, &cursor, request, map->rhs); vp; vp = fr_dcursor_next(&cursor)) { if (cond_realize_attr(request, &rhs, &rhs_cast, map->rhs, vp, da) < 0) { @@ -550,7 +551,7 @@ static bool cond_compare_attrs(request_t *request, fr_value_box_t *lhs, map_t co if (rcode != 0) break; } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return (rcode == 1); } @@ -560,7 +561,7 @@ static bool cond_compare_virtual(request_t *request, map_t const *map) fr_pair_t *virt, *vp; fr_value_box_t *rhs, rhs_cast; fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; fr_assert(tmpl_is_attr(map->lhs)); fr_assert(tmpl_is_attr(map->rhs)); @@ -568,7 +569,7 @@ static bool cond_compare_virtual(request_t *request, map_t const *map) rhs = NULL; /* shut up clang scan */ fr_value_box_clear(&rhs_cast); - for (vp = tmpl_pair_cursor_init(&rcode, request, &cc, &cursor, request, map->rhs); + for (vp = tmpl_dcursor_init(&rcode, request, &cc, &cursor, request, map->rhs); vp; vp = fr_dcursor_next(&cursor)) { if (cond_realize_attr(request, &rhs, &rhs_cast, map->rhs, vp, NULL) < 0) { @@ -592,7 +593,7 @@ static bool cond_compare_virtual(request_t *request, map_t const *map) if (rcode != 0) break; } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return (rcode == 1); } @@ -756,11 +757,11 @@ check_attrs: { fr_pair_t *vp; fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; fr_assert(!lhs); - for (vp = tmpl_pair_cursor_init(&rcode, request, &cc, &cursor, request, map->lhs); + for (vp = tmpl_dcursor_init(&rcode, request, &cc, &cursor, request, map->lhs); vp; vp = fr_dcursor_next(&cursor)) { fr_value_box_t lhs_cast; @@ -822,7 +823,7 @@ check_attrs: continue; } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); } break; diff --git a/src/lib/server/libfreeradius-server.mk b/src/lib/server/libfreeradius-server.mk index abb74e4393..3e6501cc85 100644 --- a/src/lib/server/libfreeradius-server.mk +++ b/src/lib/server/libfreeradius-server.mk @@ -35,6 +35,7 @@ SOURCES := \ snmp.c \ state.c \ stats.c \ + tmpl_dcursor.c \ tmpl_eval.c \ tmpl_tokenize.c \ trigger.c \ diff --git a/src/lib/server/map.c b/src/lib/server/map.c index 3804da5d2b..d932a4cffb 100644 --- a/src/lib/server/map.c +++ b/src/lib/server/map.c @@ -28,11 +28,12 @@ RCSID("$Id$") +#include #include #include #include #include -#include +#include #include #include @@ -1416,7 +1417,7 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f tmpl_request_ref_t request_ref; tmpl_pair_list_t list_ref; - tmpl_pair_cursor_ctx_t cc = {}; + tmpl_dcursor_ctx_t cc = {}; fr_pair_list_init(&src_list); MAP_VERIFY(map); @@ -1601,7 +1602,7 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f * the dst_list and vp pointing to the attribute or the VP * being NULL (no attribute at that index). */ - dst = tmpl_pair_cursor_init(NULL, tmp_ctx, &cc, &dst_list, request, map->lhs); + dst = tmpl_dcursor_init(NULL, tmp_ctx, &cc, &dst_list, request, map->lhs); /* * The destination is an attribute */ @@ -1723,7 +1724,7 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f * Find out what we need to build and build it */ if ((tmpl_extents_find(tmp_ctx, &leaf, &interior, request, map->lhs) < 0) || - (tmpl_extents_build_to_leaf(&leaf, &interior, map->lhs) < 0)) { + (tmpl_extents_build_to_leaf_parent(&leaf, &interior, map->lhs) < 0)) { fr_dlist_talloc_free(&leaf); fr_dlist_talloc_free(&interior); rcode = -1; @@ -1786,7 +1787,7 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f * Find out what we need to build and build it */ if ((tmpl_extents_find(tmp_ctx, &leaf, &interior, request, map->lhs) < 0) || - (tmpl_extents_build_to_leaf(&leaf, &interior, map->lhs) < 0)) { + (tmpl_extents_build_to_leaf_parent(&leaf, &interior, map->lhs) < 0)) { op_set_error: fr_dlist_talloc_free(&leaf); fr_dlist_talloc_free(&interior); @@ -1836,7 +1837,7 @@ int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t f * Find out what we need to build and build it */ if ((tmpl_extents_find(tmp_ctx, &leaf, &interior, request, map->lhs) < 0) || - (tmpl_extents_build_to_leaf(&leaf, &interior, map->lhs) < 0)) { + (tmpl_extents_build_to_leaf_parent(&leaf, &interior, map->lhs) < 0)) { fr_dlist_talloc_free(&leaf); fr_dlist_talloc_free(&interior); rcode = -1; @@ -1913,7 +1914,7 @@ update: fr_assert(fr_pair_list_empty(&src_list)); finish: - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); talloc_free(tmp_ctx); return rcode; } diff --git a/src/lib/server/map_async.c b/src/lib/server/map_async.c index 2a57499b5b..4eed8a3c7f 100644 --- a/src/lib/server/map_async.c +++ b/src/lib/server/map_async.c @@ -31,8 +31,9 @@ RCSID("$Id$") #include #include #include -#include +#include +#include #include #include @@ -538,7 +539,7 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out, case TMPL_TYPE_ATTR: { fr_dcursor_t from; - tmpl_pair_cursor_ctx_t cc_attr; + tmpl_dcursor_ctx_t cc_attr; fr_pair_t *vp; fr_value_box_t *n_vb; int err; @@ -556,7 +557,7 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out, * Check we have pairs to copy *before* * doing any expensive allocations. */ - vp = tmpl_pair_cursor_init(&err, request, &cc_attr, &from, request, mutated->rhs); + vp = tmpl_dcursor_init(&err, request, &cc_attr, &from, request, mutated->rhs); if (!vp) switch (err) { default: break; @@ -568,20 +569,20 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out, * we should delete all LHS attributes. */ if (mutated->op == T_OP_SET) n = list_mod_delete_afrom_map(ctx, original, mutated); - tmpl_pair_cursor_clear(&cc_attr); + tmpl_dursor_clear(&cc_attr); goto finish; case -2: /* No matching list */ case -3: /* No request context */ case -4: /* memory allocation error */ RPEDEBUG("Failed resolving attribute source"); - tmpl_pair_cursor_clear(&cc_attr); + tmpl_dursor_clear(&cc_attr); goto error; } n = list_mod_generic_afrom_map(ctx, original, mutated); if (!n) { - tmpl_pair_cursor_clear(&cc_attr); + tmpl_dursor_clear(&cc_attr); goto error; } @@ -593,7 +594,7 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out, attr_error: fr_dcursor_head(&values); fr_dcursor_free_list(&values); - tmpl_pair_cursor_clear(&cc_attr); + tmpl_dursor_clear(&cc_attr); goto error; } @@ -611,7 +612,7 @@ int map_to_list_mod(TALLOC_CTX *ctx, vp_list_mod_t **out, fr_dcursor_append(&values, n_vb); } while ((vp = fr_dcursor_next(&from))); - tmpl_pair_cursor_clear(&cc_attr); + tmpl_dursor_clear(&cc_attr); } break; @@ -950,7 +951,7 @@ int map_list_mod_apply(request_t *request, vp_list_mod_t const *vlm) TALLOC_CTX *parent; fr_dcursor_t list; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; memset(&cc, 0, sizeof(cc)); @@ -1088,7 +1089,7 @@ int map_list_mod_apply(request_t *request, vp_list_mod_t const *vlm) * the list and vp pointing to the attribute or the VP * being NULL (no attribute at that index). */ - found = tmpl_pair_cursor_init(NULL, request, &cc, &list, request, mod->lhs); + found = tmpl_dcursor_init(NULL, request, &cc, &list, request, mod->lhs); /* * The destination is an attribute @@ -1286,6 +1287,6 @@ int map_list_mod_apply(request_t *request, vp_list_mod_t const *vlm) } finish: - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return rcode; } diff --git a/src/lib/server/tmpl.h b/src/lib/server/tmpl.h index f572edcc90..0dfae50397 100644 --- a/src/lib/server/tmpl.h +++ b/src/lib/server/tmpl.h @@ -45,7 +45,7 @@ * functions which can be used to iterate over only the #fr_pair_t that match a * tmpl_t in a given list. * - * @see tmpl_pair_cursor_init + * @see tmpl_dcursor_init * @see tmpl_cursor_next * * Or for simplicity, there are functions which wrap the cursor functions, to copy or @@ -526,57 +526,6 @@ struct tmpl_s { ///< they ensure the correct parsing rules are applied. }; -typedef struct tmpl_cursor_ctx_s tmpl_pair_cursor_ctx_t; -typedef struct tmpl_cursor_nested_s tmpl_cursor_nested_t; - -typedef fr_pair_t *(*tmpl_cursor_eval_t)(fr_dlist_head_t *list_head, fr_pair_t *current, tmpl_cursor_nested_t *ns); - -/** State for traversing an attribute reference - * - */ -struct tmpl_cursor_nested_s { - fr_dlist_t entry; //!< Entry in the dlist. - tmpl_attr_t const *ar; //!< Attribute reference this state - ///< entry is associated with. Mainly for debugging. - tmpl_cursor_eval_t func; //!< Function used to evaluate this attribute reference. - TALLOC_CTX *list_ctx; //!< Track where we should be allocating attributes. - - union { - struct { - fr_dcursor_t cursor; //!< Group traversal is much easier - ///< but we still need to keep track - ///< where we are in the list in case - ///< we're doing counts. - } group; - - struct { - fr_pair_list_t *list_head; //!< Head of the list we're currently - ///< iterating over. - } leaf; - }; -}; - -/** Maintains state between cursor calls - * - */ -struct tmpl_cursor_ctx_s { - TALLOC_CTX *ctx; //!< Temporary allocations go here. - TALLOC_CTX *pool; //!< Temporary pool. - tmpl_t const *vpt; //!< tmpl we're evaluating. - - request_t *request; //!< Result of following the request references. - fr_pair_list_t *list; //!< List within the request. - - tmpl_cursor_nested_t leaf; //!< Pre-allocated leaf state. We always need - ///< one of these so it doesn't make sense to - ///< allocate it later. - - fr_dlist_head_t nested; //!< Nested state. These are allocated when we - ///< need to maintain state between multiple - ///< cursor calls for a particular attribute - ///< reference. -}; - /** Describes the current extents of a pair tree in relation to the tree described by a tmpl_t * */ @@ -735,21 +684,21 @@ void tmpl_verify(char const *file, int line, tmpl_t const *vpt); @code{.c} static tmpl_t list = tmpl_init_initialiser_list(CURRENT_REQUEST, PAIR_LIST_REQUEST); fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc, + tmpl_dcursor_ctx_t cc, fr_pair_t *vp; // Iterate over all pairs in the request list - for (vp = tmpl_pair_cursor_init(NULL, &cursor, request, &list); + for (vp = tmpl_dcursor_init(NULL, &cursor, request, &list); vp; vp = tmpl_cursor_next(&cursor, &list)) { // Do something } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); @endcode * * @param _request to locate the list in. * @param _list to set as the target for the template. - * @see tmpl_pair_cursor_init + * @see tmpl_dcursor_init * @see tmpl_cursor_next */ #define tmpl_init_initialiser_list(_request, _list)\ @@ -1012,12 +961,6 @@ ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out, fr_type_t dst_type) CC_HINT(nonnull (2, 3, 4)); -fr_pair_t *tmpl_pair_cursor_init(int *err, TALLOC_CTX *ctx, tmpl_pair_cursor_ctx_t *cc, - fr_dcursor_t *cursor, request_t *request, - tmpl_t const *vpt); - -void tmpl_pair_cursor_clear(tmpl_pair_cursor_ctx_t *cc); - int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt); @@ -1032,7 +975,7 @@ int tmpl_extents_find(TALLOC_CTX *ctx, fr_dlist_head_t *leaf, fr_dlist_head_t *interior, request_t *request, tmpl_t const *vpt); -int tmpl_extents_build_to_leaf(fr_dlist_head_t *leaf, fr_dlist_head_t *interior, +int tmpl_extents_build_to_leaf_parent(fr_dlist_head_t *leaf, fr_dlist_head_t *interior, tmpl_t const *vpt); void tmpl_extents_debug(fr_dlist_head_t *head); diff --git a/src/lib/server/tmpl_dcursor.c b/src/lib/server/tmpl_dcursor.c new file mode 100644 index 0000000000..b9f9abcc0e --- /dev/null +++ b/src/lib/server/tmpl_dcursor.c @@ -0,0 +1,722 @@ +/* + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * $Id$ + * + * @brief #fr_pair_t template functions + * @file src/lib/server/tmpl_cursor.c + * + * @ingroup AVP + * + * @copyright 2020-2021 Arran Cudbard-Bell + */ +RCSID("$Id$") + +#include +#include +#include +#include +#include +#include +#include +#include + +static inline CC_HINT(always_inline) +void _tmpl_cursor_pool_init(tmpl_dcursor_ctx_t *cc) +{ + if (!cc->pool) MEM(cc->pool = talloc_pool(cc->ctx, sizeof(tmpl_dcursor_nested_t) * 5)); +} + +/** Traverse a group attribute + * + * Here we just look for a particular group attribute in the context of its parent + * + * @param[in] list_head The head of the pair_list being evaluated. + * @param[in] current The pair to evaluate. + * @param[in] ns Tracks tree position between cursor calls. + * @return + * - the next matching attribute + * - NULL if none found + */ +static fr_pair_t *_tmpl_cursor_child_eval(UNUSED fr_dlist_head_t *list_head, UNUSED fr_pair_t *current, tmpl_dcursor_nested_t *ns) +{ + fr_pair_t *vp; + + for (vp = fr_dcursor_current(&ns->group.cursor); + vp; + vp = fr_dcursor_next(&ns->group.cursor)) { + if (fr_dict_attr_cmp(ns->ar->ar_da, vp->da) == 0) { + fr_dcursor_next(&ns->group.cursor); /* Advance to correct position for next call */ + return vp; + } + } + + return NULL; +} + +/** Initialise the evaluation context for traversing a group attribute + * + */ +static inline CC_HINT(always_inline) +void _tmpl_cursor_child_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_dcursor_ctx_t *cc) +{ + tmpl_dcursor_nested_t *ns; + + _tmpl_cursor_pool_init(cc); + MEM(ns = talloc(cc->pool, tmpl_dcursor_nested_t)); + *ns = (tmpl_dcursor_nested_t){ + .ar = ar, + .func = _tmpl_cursor_child_eval, + .list_ctx = list_ctx + }; + fr_pair_dcursor_init(&ns->group.cursor, list); + fr_dlist_insert_tail(&cc->nested, ns); +} + +/** Find a leaf attribute + * + * @param[in] list_head The head of the pair_list being evaluated. + * @param[in] curr The current attribute to start searching from. + * @param[in] ns Tracks tree position between cursor calls. + * @return + * - the next matching attribute + * - NULL if none found + */ +static fr_pair_t *_tmpl_cursor_leaf_eval(fr_dlist_head_t *list_head, fr_pair_t *curr, tmpl_dcursor_nested_t *ns) +{ + fr_pair_t *vp = curr; + + while (vp) { + if (fr_dict_attr_cmp(ns->ar->ar_da, vp->da) == 0) return vp; + vp = fr_dlist_next(list_head, vp); + } + + return NULL; +} + +/** Initialise the evaluation context for finding a leaf attribute + * + */ +static inline CC_HINT(always_inline) +void _tmpl_cursor_leaf_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_dcursor_ctx_t *cc) +{ + tmpl_dcursor_nested_t *ns = &cc->leaf; + + *ns = (tmpl_dcursor_nested_t){ + .ar = ar, + .func = _tmpl_cursor_leaf_eval, + .list_ctx = list_ctx + }; + ns->leaf.list_head = list; + fr_dlist_insert_tail(&cc->nested, ns); +} + +/** Stub list eval function until we can remove lists + * + */ +static fr_pair_t *_tmpl_cursor_list_eval(UNUSED fr_dlist_head_t *list_head, fr_pair_t *curr, UNUSED tmpl_dcursor_nested_t *ns) +{ + return curr; +} + +static inline CC_HINT(always_inline) +void _tmpl_cursor_list_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_dcursor_ctx_t *cc) +{ + tmpl_dcursor_nested_t *ns; + + ns = &cc->leaf; + *ns = (tmpl_dcursor_nested_t){ + .ar = ar, + .func = _tmpl_cursor_list_eval, + .list_ctx = list_ctx + }; + ns->leaf.list_head = list; + fr_dlist_insert_tail(&cc->nested, ns); +} + +static inline CC_HINT(always_inline) void _tmpl_cursor_common_pop(tmpl_dcursor_ctx_t *cc) +{ + tmpl_dcursor_nested_t *ns = fr_dlist_pop_tail(&cc->nested); + + if (ns != &cc->leaf) talloc_free(ns); +} + +/** Evaluates, then, sometimes, pops evaluation contexts from the tmpl stack + * + * To pop or not to pop is determined by whether evaluating the context again + * would/should/could produce another fr_pair_t. + * + * @param[in] list_head The head of the pair_list being evaluated. + * @param[in] curr The pair to evaluate. + * @param[in] cc Tracks state between cursor calls. + * @return the vp evaluated. + */ +static inline CC_HINT(always_inline) +fr_pair_t *_tmpl_cursor_eval(fr_dlist_head_t *list_head, fr_pair_t *curr, tmpl_dcursor_ctx_t *cc) +{ + tmpl_attr_t const *ar; + tmpl_dcursor_nested_t *ns; + fr_pair_t *iter = curr, *vp; + + ns = fr_dlist_tail(&cc->nested); + ar = ns->ar; + + if (ar) switch (ar->ar_num) { + /* + * Get the first instance + */ + case NUM_ANY: + vp = ns->func(list_head, curr, ns); + _tmpl_cursor_common_pop(cc); + break; + + /* + * Get all instances + */ + case NUM_ALL: + case NUM_COUNT: + all_inst: + vp = ns->func(list_head, curr, ns); + if (!vp) _tmpl_cursor_common_pop(cc); /* pop only when we're done */ + break; + + /* + * Get the last instance + */ + case NUM_LAST: + vp = NULL; + while ((iter = ns->func(list_head, iter, ns))) { + vp = iter; + + if (!fr_dlist_next(list_head, vp)) break; + + iter = fr_dlist_next(list_head,vp); + } + _tmpl_cursor_common_pop(cc); + break; + + /* + * Get the n'th instance + */ + default: + { + int16_t i = 0; + + for (;;) { + vp = ns->func(list_head, iter, ns); + if (!vp) break; /* Prev and next at the correct points */ + + if (++i > ar->num) break; + + iter = fr_dlist_next(list_head, vp); + }; + _tmpl_cursor_common_pop(cc); + } + break; + } else goto all_inst; /* Used for TMPL_TYPE_LIST */ + + return vp; +} + +static inline CC_HINT(always_inline) +void _tmpl_cursor_pair_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_dcursor_ctx_t *cc) +{ + if (fr_dlist_next(&cc->vpt->data.attribute.ar, ar)) switch (ar->ar_da->type) { + case FR_TYPE_STRUCTURAL: + _tmpl_cursor_child_init(list_ctx, list, ar, cc); + break; + + default: + leaf: + _tmpl_cursor_leaf_init(list_ctx, list, ar, cc); + break; + } else goto leaf; +} + +static void *_tmpl_cursor_next(fr_dlist_head_t *list, void *curr, void *uctx) +{ + tmpl_dcursor_ctx_t *cc = uctx; + tmpl_t const *vpt = cc->vpt; + + fr_pair_t *vp; + fr_pair_list_t *list_head; + + switch (vpt->type) { + case TMPL_TYPE_ATTR: + { + tmpl_attr_t const *ar = NULL; + tmpl_dcursor_nested_t *ns = NULL; + + /* + * - Continue until there are no evaluation contexts + * - Push a evaluation context if evaluating the head of the + * stack yields a VP and we're not at the deepest attribute + * reference. + * - Return if we have a VP and there are no more attribute + * references to push, i.e. we're at the deepest attribute + * reference. + */ + while ((ns = fr_dlist_tail(&cc->nested))) { + ar = ns->ar; + vp = _tmpl_cursor_eval(list, curr, cc); + if (!vp) continue; + + ar = fr_dlist_next(&vpt->data.attribute.ar, ar); + if (ar) { + list_head = &vp->vp_group; + _tmpl_cursor_pair_init(vp, list_head, ar, cc); + curr = fr_pair_list_head(list_head); + list = UNCONST(fr_dlist_head_t *, fr_pair_list_order(list_head)); + continue; + } + + return vp; + } + + null_result: + return NULL; + } + + /* + * Hacks for evaluating lists + * Hopefully this tmpl type goes away soon... + */ + case TMPL_TYPE_LIST: + if (!fr_dlist_tail(&cc->nested)) goto null_result; /* end of list */ + + vp = _tmpl_cursor_eval(list, curr, cc); + if (!vp) goto null_result; + + return vp; + + default: + fr_assert(0); + } + + return NULL; +} + +/** Initialise a #fr_dcursor_t to the #fr_pair_t specified by a #tmpl_t + * + * This makes iterating over the one or more #fr_pair_t specified by a #tmpl_t + * significantly easier. + * + * @param[out] err May be NULL if no error code is required. + * Will be set to: + * - 0 on success. + * - -1 if no matching #fr_pair_t could be found. + * - -2 if list could not be found (doesn't exist in current #request_t). + * - -3 if context could not be found (no parent #request_t available). + * @param[in] ctx to make temporary allocations under. + * @param[in] cc to initialise. Tracks evaluation state. + * Must be explicitly cleared with tmpl_cursor_state_clear + * otherwise we will leak memory. + * @param[in] cursor to store iterator position. + * @param[in] request The current #request_t. + * @param[in] vpt specifying the #fr_pair_t type or list to iterate over. + * @return + * - First #fr_pair_t specified by the #tmpl_t. + * - NULL if no matching #fr_pair_t found, and NULL on error. + * + * @see tmpl_cursor_next + */ +fr_pair_t *tmpl_dcursor_init(int *err, TALLOC_CTX *ctx, tmpl_dcursor_ctx_t *cc, + fr_dcursor_t *cursor, request_t *request, tmpl_t const *vpt) +{ + fr_pair_t *vp = NULL; + fr_pair_list_t *list_head; + tmpl_request_t *rr = NULL; + TALLOC_CTX *list_ctx; + + TMPL_VERIFY(vpt); + + fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt)); + + if (err) *err = 0; + + /* + * Navigate to the correct request context + */ + while ((rr = fr_dlist_next(&vpt->data.attribute.rr, rr))) { + if (tmpl_request_ptr(&request, rr->request) < 0) { + if (err) { + *err = -3; + fr_strerror_printf("Request context \"%s\" not available", + fr_table_str_by_value(tmpl_request_ref_table, rr->request, "")); + } + error: + memset(cc, 0, sizeof(*cc)); /* so tmpl_dursor_clear doesn't explode */ + return NULL; + } + } + + /* + * Get the right list in the specified context + */ + list_head = tmpl_list_head(request, tmpl_list(vpt)); + if (!list_head) { + if (err) { + *err = -2; + fr_strerror_printf("List \"%s\" not available in this context", + fr_table_str_by_value(pair_list_table, tmpl_list(vpt), "")); + } + goto error; + } + list_ctx = tmpl_list_ctx(request, tmpl_list(vpt)); + + /* + * Initialise the temporary cursor context + */ + *cc = (tmpl_dcursor_ctx_t){ + .vpt = vpt, + .ctx = ctx, + .request = request, + .list = list_head + }; + fr_dlist_init(&cc->nested, tmpl_dcursor_nested_t, entry); + + /* + * Prime the stack! + */ + switch (vpt->type) { + case TMPL_TYPE_ATTR: + _tmpl_cursor_pair_init(list_ctx, cc->list, fr_dlist_head(&vpt->data.attribute.ar), cc); + break; + + case TMPL_TYPE_LIST: + _tmpl_cursor_list_init(list_ctx, cc->list, fr_dlist_head(&vpt->data.attribute.ar), cc); + break; + + default: + fr_assert(0); + break; + } + + /* + * Get the first entry from the tmpl + */ + vp = fr_pair_dcursor_iter_init(cursor, list_head, _tmpl_cursor_next, cc); + if (!vp) { + if (err) { + *err = -1; + if (tmpl_is_list(vpt)) { + fr_strerror_printf("List \"%s\" is empty", vpt->name); + } else { + fr_strerror_printf("No matching \"%s\" pairs found", tmpl_da(vpt)->name); + } + } + return NULL; + } + + return vp; +} + +/** Clear any temporary state allocations + * + */ +void tmpl_dursor_clear(tmpl_dcursor_ctx_t *cc) +{ + if (!fr_dlist_num_elements(&cc->nested)) return;/* Help simplify dealing with unused cursor ctxs */ + + fr_dlist_remove(&cc->nested, &cc->leaf); /* Noop if leaf isn't inserted */ + fr_dlist_talloc_free(&cc->nested); + + /* + * Always free the pool because it's allocated when + * any nested ctxs are used. + */ + TALLOC_FREE(cc->pool); +} + + +#define EXTENT_ADD(_out, _ar, _list_ctx, _list) \ + do { \ + tmpl_attr_extent_t *_extent; \ + MEM(_extent = talloc(ctx, tmpl_attr_extent_t)); \ + *_extent = (tmpl_attr_extent_t){ \ + .ar = _ar, \ + .list_ctx = _list_ctx, \ + .list = _list \ + }; \ + fr_dlist_insert_tail(_out, _extent); \ + } while (0) + +/** Determines points where the reference list extends beyond the current pair tree + * + * If a particular branch in the VP hierarchy is incomplete, i.e. the chain of attribute + * refers to nodes deeper than the nodes currently in the tree, then we return the + * deepest point node in the tree which matched, and the ar that we failed to evaluate. + * + * If the reference list resolves to one or more structural pairs, return those as well. + * + * This function can be used for a number of different operations, but it's most useful + * for determining insertion points for new attributes, or determining which attributes + * need to be updated. + * + * @param[in] ctx to allocate. It's recommended to pass a pool with space + * for at least five extent structures. + * @param[out] existing List of extents we discovered by evaluating all + * attribute references. May be NULL. + * @param[out] to_build List of extents that need building out, i.e. references + * extend beyond pairs. May be NULL. + * @param[in] request The current #request_t. + * @param[in] vpt specifying the #fr_pair_t type to retrieve or create. + * Must be #TMPL_TYPE_ATTR. + * @return + * - 0 on success a pair was found. + * - -2 if list could not be found (doesn't exist in current #request_t). + * - -3 if context could not be found (no parent #request_t available). + */ +int tmpl_extents_find(TALLOC_CTX *ctx, + fr_dlist_head_t *existing, fr_dlist_head_t *to_build, + request_t *request, tmpl_t const *vpt) +{ + fr_pair_t *curr = NULL; + fr_pair_list_t *list_head; + + TALLOC_CTX *list_ctx = NULL; + + tmpl_dcursor_ctx_t cc; + tmpl_dcursor_nested_t *ns = NULL; + + tmpl_request_t *rr = NULL; + tmpl_attr_t const *ar = NULL; + + TMPL_VERIFY(vpt); + + fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt)); + + /* + * Navigate to the correct request context + */ + while ((rr = fr_dlist_next(&vpt->data.attribute.rr, rr))) { + if (tmpl_request_ptr(&request, rr->request) < 0) { + fr_strerror_printf("Request context \"%s\" not available", + fr_table_str_by_value(tmpl_request_ref_table, rr->request, "")); + return -3; + } + } + + /* + * Get the right list in the specified context + */ + list_head = tmpl_list_head(request, tmpl_list(vpt)); + if (!list_head) { + fr_strerror_printf("List \"%s\" not available in this context", + fr_table_str_by_value(pair_list_table, tmpl_list(vpt), "")); + return -2; + } + list_ctx = tmpl_list_ctx(request, tmpl_list(vpt)); + + /* + * If it's a list, just return the list head + */ + if (vpt->type == TMPL_TYPE_LIST) { + do_list: + if (existing) EXTENT_ADD(existing, NULL, list_ctx, list_head); + return 0; + } + + /* + * If it's a leaf skip all the expensive + * initialisation and just return the list + * it's part of. + * + * This is only needed because lists are + * treated specially. Once lists are groups + * this can be removed. + */ + ar = fr_dlist_head(&vpt->data.attribute.ar); + switch (ar->ar_da->type) { + case FR_TYPE_STRUCTURAL: + break; + + default: + goto do_list; + } + + /* + * Initialise the temporary cursor context + */ + cc = (tmpl_dcursor_ctx_t){ + .vpt = vpt, + .ctx = ctx, + .request = request, + .list = list_head + }; + fr_dlist_init(&cc.nested, tmpl_dcursor_nested_t, entry); + + /* + * Prime the stack! + */ + _tmpl_cursor_pair_init(list_ctx, cc.list, fr_dlist_head(&vpt->data.attribute.ar), &cc); + + /* + * - Continue until there are no evaluation contexts + * - Push a evaluation context if evaluating the head of the + * stack yields a VP and we're not at the deepest attribute + * reference. + * - Return if we have a VP and there are no more attribute + * references to push, i.e. we're at the deepest attribute + * reference. + */ + curr = fr_pair_list_head(list_head); + while ((ns = fr_dlist_tail(&cc.nested))) { + tmpl_attr_t const *n_ar; + + list_ctx = ns->list_ctx; + ar = ns->ar; + curr = _tmpl_cursor_eval(&list_head->order, curr, &cc); + if (!curr) { + /* + * References extend beyond current + * pair tree. + */ + if (!ar->resolve_only && to_build) EXTENT_ADD(to_build, ar, list_ctx, list_head); + continue; /* Rely on _tmpl_cursor_eval popping the stack */ + } + + /* + * Evaluate the next reference + */ + n_ar = fr_dlist_next(&vpt->data.attribute.ar, ar); + if (n_ar) { + ar = n_ar; + list_head = &curr->vp_group; + list_ctx = curr; /* Allocations are under the group */ + _tmpl_cursor_pair_init(list_ctx, list_head, ar, &cc); + curr = fr_pair_list_head(list_head); + continue; + } + + /* + * Only reached when we can't find an exiting + * part of the pair_root to keep walking. + * + * VP tree may extend beyond the reference. + * If the reference was structural, record this + * as an extent. + */ + if (existing) switch (ar->da->type) { + case FR_TYPE_STRUCTURAL: + EXTENT_ADD(existing, NULL, curr, list_head); + break; + + default: + break; + } + } + + return 0; +} + +/** Allocate interior pairs + * + * Builds out the pair tree to the point where leaf attributes can be added + * + * @param[out] existing List to add built out attributes to. + * @param[in] to_build List to remove attributes from. + * @param[in] vpt We are evaluating. + * @return + * - 0 on success. + * - -1 on failure. + */ +int tmpl_extents_build_to_leaf_parent(fr_dlist_head_t *existing, fr_dlist_head_t *to_build, tmpl_t const *vpt) +{ + tmpl_attr_extent_t *extent = NULL; + + while ((extent = fr_dlist_head(to_build))) { + fr_pair_list_t *list; + TALLOC_CTX *list_ctx; + fr_pair_t *vp; + tmpl_attr_t const *ar; + + fr_assert(extent->ar); /* Interior extents MUST contain an ar */ + + /* + * Try and allocate VPs for the + * rest of the attribute references. + */ + for (ar = extent->ar, list = extent->list, list_ctx = extent->list_ctx; + ar; + ar = fr_dlist_next(&vpt->data.attribute.ar, ar)) { + switch (ar->type) { + case TMPL_ATTR_TYPE_NORMAL: + case TMPL_ATTR_TYPE_UNKNOWN: + /* + * Don't build leaf attributes + */ + if (!fr_type_is_structural(ar->ar_da->type)) continue; + + MEM(vp = fr_pair_afrom_da(list_ctx, ar->ar_da)); /* Copies unknowns */ + fr_pair_append(list, vp); + list = &vp->vp_group; + list_ctx = vp; /* New allocations occur under the VP */ + break; + + default: + fr_assert_fail("references of this type should have been resolved"); + return -1; + } + } + + fr_dlist_remove(to_build, extent); /* Do this *before* zeroing the dlist headers */ + *extent = (tmpl_attr_extent_t){ + .list = list, + .list_ctx = list_ctx + }; + fr_dlist_insert_tail(existing, extent); /* move between in and out */ + } + + return 0; +} + +void tmpl_extents_debug(fr_dlist_head_t *head) +{ + tmpl_attr_extent_t const *extent = NULL; + fr_pair_t *vp = NULL; + + for (extent = fr_dlist_head(head); + extent; + extent = fr_dlist_next(head, extent)) { + tmpl_attr_t const *ar = extent->ar; + char const *ctx_name; + + if (ar) { + FR_FAULT_LOG("extent-interior-attr"); + tmpl_attr_ref_debug(extent->ar, 0); + } else { + FR_FAULT_LOG("extent-leaf"); + } + + ctx_name = talloc_get_name(extent->list_ctx); + if (strcmp(ctx_name, "fr_pair_t") == 0) { + FR_FAULT_LOG("list_ctx : %p (%s, %s)", extent->list_ctx, ctx_name, + ((fr_pair_t *)extent->list_ctx)->da->name); + } else { + FR_FAULT_LOG("list_ctx : %p (%s)", extent->list_ctx, ctx_name); + } + FR_FAULT_LOG("list : %p", extent->list); + if (fr_pair_list_empty(extent->list)) { + FR_FAULT_LOG("list (first) : none (%p)", extent->list); + } else { + vp = fr_pair_list_head(extent->list); + FR_FAULT_LOG("list (first) : %s (%p)", vp->da->name, extent->list); + } + } + +} diff --git a/src/lib/server/tmpl_dcursor.h b/src/lib/server/tmpl_dcursor.h new file mode 100644 index 0000000000..c75cd06631 --- /dev/null +++ b/src/lib/server/tmpl_dcursor.h @@ -0,0 +1,100 @@ +#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 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 St, Fifth Floor, Boston, MA 02110-1301, USA + */ + + +#include +#include + +RCSIDH(tmpl_dcursor_t, "$Id$") + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct tmpl_dcursor_ctx_s tmpl_dcursor_ctx_t; +typedef struct tmpl_dcursor_nested_s tmpl_dcursor_nested_t; + +/** Evaluation function for iterating over a given type of attribute + * + * Currently attributes are divided into structural and leaf attributes, + * so we need an evaluation function for each of those. + * + * @param[in] list_head to evaluate. + * @param[in] current position in the list. + * @param[in] ns Nested state. + */ +typedef fr_pair_t *(*tmpl_dursor_eval_t)(fr_dlist_head_t *list_head, fr_pair_t *current, tmpl_dcursor_nested_t *ns); + +/** State for traversing an attribute reference + * + */ +struct tmpl_dcursor_nested_s { + fr_dlist_t entry; //!< Entry in the dlist that forms the evaluation stack. + tmpl_attr_t const *ar; //!< Attribute reference this state + ///< entry is associated with. Mainly for debugging. + tmpl_dursor_eval_t func; //!< Function used to evaluate this attribute reference. + TALLOC_CTX *list_ctx; //!< Track where we should be allocating attributes. + + bool seen; //!< Whether we've seen an attribute at this level of + ///< evaluation already. This is mainly used where + ///< the build cursor is used. + + union { + struct { + fr_dcursor_t cursor; //!< Group traversal is much easier + ///< but we still need to keep track + ///< where we are in the list in case + ///< we're doing counts. + } group; + + struct { + fr_pair_list_t *list_head; //!< Head of the list we're currently + ///< iterating over. + } leaf; + }; +}; + +/** Maintains state between cursor calls + * + */ +struct tmpl_dcursor_ctx_s { + TALLOC_CTX *ctx; //!< Temporary allocations go here. + TALLOC_CTX *pool; //!< Temporary pool. + tmpl_t const *vpt; //!< tmpl we're evaluating. + + request_t *request; //!< Result of following the request references. + + fr_pair_list_t *list; //!< List within the request. + + fr_dlist_head_t nested; //!< Nested state. These are allocated when we + ///< need to maintain state between multiple + ///< cursor calls for a particular attribute + ///< reference. + ///< This forms a stack of tmpl_dcursor_nested_t + ///< and tracks where we are in evaluation at + ///< all levels. + + tmpl_dcursor_nested_t leaf; //!< Pre-allocated leaf state. We always need + ///< one of these so it doesn't make sense to + ///< allocate it later. +}; + +fr_pair_t *tmpl_dcursor_init(int *err, TALLOC_CTX *ctx, tmpl_dcursor_ctx_t *cc, + fr_dcursor_t *cursor, request_t *request, + tmpl_t const *vpt); + +void tmpl_dursor_clear(tmpl_dcursor_ctx_t *cc); diff --git a/src/lib/server/tmpl_eval.c b/src/lib/server/tmpl_eval.c index 9ed98fb936..223693d996 100644 --- a/src/lib/server/tmpl_eval.c +++ b/src/lib/server/tmpl_eval.c @@ -31,9 +31,11 @@ RCSID("$Id$") #include #include #include +#include #include #include #include +#include /** Resolve attribute #pair_list_t value to an attribute list. * @@ -45,7 +47,7 @@ RCSID("$Id$") * name couldn't be resolved. * @return a pointer to the HEAD of a list in the #request_t. * - * @see tmpl_pair_cursor_init + * @see tmpl_dcursor_init */ fr_pair_list_t *tmpl_list_head(request_t *request, tmpl_pair_list_t list) { @@ -778,440 +780,6 @@ ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out, return from_cast.vb_length; } -static inline CC_HINT(always_inline) -void _tmpl_cursor_pool_init(tmpl_pair_cursor_ctx_t *cc) -{ - if (!cc->pool) MEM(cc->pool = talloc_pool(cc->ctx, sizeof(tmpl_cursor_nested_t) * 5)); -} - -/** Traverse a group attribute - * - * Here we just look for a particular group attribute in the context of its parent - * - * @param[in] list_head The head of the pair_list being evaluated. - * @param[in] current The pair to evaluate. - * @param[in] ns Tracks tree position between cursor calls. - * @return - * - the next matching attribute - * - NULL if none found - */ -static fr_pair_t *_tmpl_cursor_child_eval(UNUSED fr_dlist_head_t *list_head, UNUSED fr_pair_t *current, tmpl_cursor_nested_t *ns) -{ - fr_pair_t *vp; - - for (vp = fr_dcursor_current(&ns->group.cursor); - vp; - vp = fr_dcursor_next(&ns->group.cursor)) { - if (fr_dict_attr_cmp(ns->ar->ar_da, vp->da) == 0) { - fr_dcursor_next(&ns->group.cursor); /* Advance to correct position for next call */ - return vp; - } - } - - return NULL; -} - -/** Initialise the evaluation context for traversing a group attribute - * - */ -static inline CC_HINT(always_inline) -void _tmpl_cursor_child_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_pair_cursor_ctx_t *cc) -{ - tmpl_cursor_nested_t *ns; - - _tmpl_cursor_pool_init(cc); - MEM(ns = talloc(cc->pool, tmpl_cursor_nested_t)); - *ns = (tmpl_cursor_nested_t){ - .ar = ar, - .func = _tmpl_cursor_child_eval, - .list_ctx = list_ctx - }; - fr_pair_dcursor_init(&ns->group.cursor, list); - fr_dlist_insert_tail(&cc->nested, ns); -} - -/** Find a leaf attribute - * - * @param[in] list_head The head of the pair_list being evaluated. - * @param[in] curr The current attribute to start searching from. - * @param[in] ns Tracks tree position between cursor calls. - * @return - * - the next matching attribute - * - NULL if none found - */ -static fr_pair_t *_tmpl_cursor_leaf_eval(fr_dlist_head_t *list_head, fr_pair_t *curr, tmpl_cursor_nested_t *ns) -{ - fr_pair_t *vp = curr; - - while (vp) { - if (fr_dict_attr_cmp(ns->ar->ar_da, vp->da) == 0) return vp; - vp = fr_dlist_next(list_head, vp); - } - - return NULL; -} - -/** Initialise the evaluation context for finding a leaf attribute - * - */ -static inline CC_HINT(always_inline) -void _tmpl_cursor_leaf_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_pair_cursor_ctx_t *cc) -{ - tmpl_cursor_nested_t *ns = &cc->leaf; - - *ns = (tmpl_cursor_nested_t){ - .ar = ar, - .func = _tmpl_cursor_leaf_eval, - .list_ctx = list_ctx - }; - ns->leaf.list_head = list; - fr_dlist_insert_tail(&cc->nested, ns); -} - -/** Stub list eval function until we can remove lists - * - */ -static fr_pair_t *_tmpl_cursor_list_eval(UNUSED fr_dlist_head_t *list_head, fr_pair_t *curr, UNUSED tmpl_cursor_nested_t *ns) -{ - return curr; -} - -static inline CC_HINT(always_inline) -void _tmpl_cursor_list_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_pair_cursor_ctx_t *cc) -{ - tmpl_cursor_nested_t *ns; - - ns = &cc->leaf; - *ns = (tmpl_cursor_nested_t){ - .ar = ar, - .func = _tmpl_cursor_list_eval, - .list_ctx = list_ctx - }; - ns->leaf.list_head = list; - fr_dlist_insert_tail(&cc->nested, ns); -} - -static inline CC_HINT(always_inline) void _tmpl_cursor_eval_pop(tmpl_pair_cursor_ctx_t *cc) -{ - tmpl_cursor_nested_t *ns = fr_dlist_pop_tail(&cc->nested); - - if (ns != &cc->leaf) talloc_free(ns); -} - -/** Evaluates, then, sometimes, pops evaluation contexts from the tmpl stack - * - * To pop or not to pop is determined by whether evaluating the context again - * would/should/could produce another fr_pair_t. - * - * @param[in] list_head The head of the pair_list being evaluated. - * @param[in] curr The pair to evaluate. - * @param[in] cc Tracks state between cursor calls. - * @return the vp evaluated. - */ -static inline CC_HINT(always_inline) -fr_pair_t *_tmpl_cursor_eval(fr_dlist_head_t *list_head, fr_pair_t *curr, tmpl_pair_cursor_ctx_t *cc) -{ - tmpl_attr_t const *ar; - tmpl_cursor_nested_t *ns; - fr_pair_t *iter = curr, *vp; - - ns = fr_dlist_tail(&cc->nested); - ar = ns->ar; - - if (ar) switch (ar->ar_num) { - /* - * Get the first instance - */ - case NUM_ANY: - vp = ns->func(list_head, curr, ns); - _tmpl_cursor_eval_pop(cc); - break; - - /* - * Get all instances - */ - case NUM_ALL: - case NUM_COUNT: - all_inst: - vp = ns->func(list_head, curr, ns); - if (!vp) _tmpl_cursor_eval_pop(cc); /* pop only when we're done */ - break; - - /* - * Get the last instance - */ - case NUM_LAST: - vp = NULL; - while ((iter = ns->func(list_head, iter, ns))) { - vp = iter; - - if (!fr_dlist_next(list_head, vp)) break; - - iter = fr_dlist_next(list_head,vp); - } - _tmpl_cursor_eval_pop(cc); - break; - - /* - * Get the n'th instance - */ - default: - { - int16_t i = 0; - - for (;;) { - vp = ns->func(list_head, iter, ns); - if (!vp) break; /* Prev and next at the correct points */ - - if (++i > ar->num) break; - - iter = fr_dlist_next(list_head, vp); - }; - _tmpl_cursor_eval_pop(cc); - } - break; - } else goto all_inst; /* Used for TMPL_TYPE_LIST */ - - return vp; -} - -static inline CC_HINT(always_inline) -void _tmpl_pair_cursor_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_pair_cursor_ctx_t *cc) -{ - if (fr_dlist_next(&cc->vpt->data.attribute.ar, ar)) switch (ar->ar_da->type) { - case FR_TYPE_STRUCTURAL: - _tmpl_cursor_child_init(list_ctx, list, ar, cc); - break; - - default: - leaf: - _tmpl_cursor_leaf_init(list_ctx, list, ar, cc); - break; - } else goto leaf; -} - -static void *_tmpl_cursor_next(fr_dlist_head_t *list, void *curr, void *uctx) -{ - tmpl_pair_cursor_ctx_t *cc = uctx; - tmpl_t const *vpt = cc->vpt; - - fr_pair_t *vp; - fr_pair_list_t *list_head; - - switch (vpt->type) { - case TMPL_TYPE_ATTR: - { - tmpl_attr_t const *ar = NULL; - tmpl_cursor_nested_t *ns = NULL; - - /* - * - Continue until there are no evaluation contexts - * - Push a evaluation context if evaluating the head of the - * stack yields a VP and we're not at the deepest attribute - * reference. - * - Return if we have a VP and there are no more attribute - * references to push, i.e. we're at the deepest attribute - * reference. - */ - while ((ns = fr_dlist_tail(&cc->nested))) { - ar = ns->ar; - vp = _tmpl_cursor_eval(list, curr, cc); - if (!vp) continue; - - ar = fr_dlist_next(&vpt->data.attribute.ar, ar); - if (ar) { - list_head = &vp->vp_group; - _tmpl_pair_cursor_init(vp, list_head, ar, cc); - curr = fr_pair_list_head(list_head); - list = UNCONST(fr_dlist_head_t *, fr_pair_list_order(list_head)); - continue; - } - - return vp; - } - - null_result: - return NULL; - } - - /* - * Hacks for evaluating lists - * Hopefully this tmpl type goes away soon... - */ - case TMPL_TYPE_LIST: - if (!fr_dlist_tail(&cc->nested)) goto null_result; /* end of list */ - - vp = _tmpl_cursor_eval(list, curr, cc); - if (!vp) goto null_result; - - return vp; - - default: - fr_assert(0); - } - - return NULL; -} - -/** Initialise a #fr_dcursor_t to the #fr_pair_t specified by a #tmpl_t - * - * This makes iterating over the one or more #fr_pair_t specified by a #tmpl_t - * significantly easier. - * - * @param[out] err May be NULL if no error code is required. - * Will be set to: - * - 0 on success. - * - -1 if no matching #fr_pair_t could be found. - * - -2 if list could not be found (doesn't exist in current #request_t). - * - -3 if context could not be found (no parent #request_t available). - * @param[in] ctx to make temporary allocations under. - * @param[in] cc to initialise. Tracks evaluation state. - * Must be explicitly cleared with tmpl_cursor_state_clear - * otherwise we will leak memory. - * @param[in] cursor to store iterator position. - * @param[in] request The current #request_t. - * @param[in] vpt specifying the #fr_pair_t type or list to iterate over. - * @return - * - First #fr_pair_t specified by the #tmpl_t. - * - NULL if no matching #fr_pair_t found, and NULL on error. - * - * @see tmpl_cursor_next - */ -fr_pair_t *tmpl_pair_cursor_init(int *err, TALLOC_CTX *ctx, tmpl_pair_cursor_ctx_t *cc, - fr_dcursor_t *cursor, request_t *request, tmpl_t const *vpt) -{ - fr_pair_t *vp = NULL; - fr_pair_list_t *list_head = NULL; - tmpl_request_t *rr = NULL; - TALLOC_CTX *list_ctx = NULL; - - TMPL_VERIFY(vpt); - - fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt)); - - if (err) *err = 0; - - /* - * Navigate to the correct request context - */ - while ((rr = fr_dlist_next(&vpt->data.attribute.rr, rr))) { - if (tmpl_request_ptr(&request, rr->request) < 0) { - if (err) { - *err = -3; - fr_strerror_printf("Request context \"%s\" not available", - fr_table_str_by_value(tmpl_request_ref_table, rr->request, "")); - } - error: - memset(cc, 0, sizeof(*cc)); /* so tmpl_pair_cursor_clear doesn't explode */ - return NULL; - } - } - - /* - * If the rules say "return the list as an attribute", - * then check for that. But if the first da isn't a - * list, then default to whatever list ref is given. - * - * @todo - for the future, have the tokenizer (or - * whatever) always add the list head to the list of - * attribute references. - */ - if (vpt->rules.list_as_attr) { - tmpl_attr_t const *ar; - - ar = fr_dlist_head(&vpt->data.attribute.ar); - fr_assert(ar != NULL); - - if ((ar->ar_da == request_attr_request) || - (ar->ar_da == request_attr_reply) || - (ar->ar_da == request_attr_control) || - (ar->ar_da == request_attr_state)) { - list_head = &request->pair_root->vp_group; - list_ctx = request->pair_root; - } - } - - if (!list_head) { - /* - * Get the right list in the specified context - */ - list_head = tmpl_list_head(request, tmpl_list(vpt)); - if (!list_head) { - if (err) { - *err = -2; - fr_strerror_printf("List \"%s\" not available in this context", - fr_table_str_by_value(pair_list_table, tmpl_list(vpt), "")); - } - goto error; - } - list_ctx = tmpl_list_ctx(request, tmpl_list(vpt)); - } - fr_assert(list_ctx != NULL); - - /* - * Initialise the temporary cursor context - */ - *cc = (tmpl_pair_cursor_ctx_t){ - .vpt = vpt, - .ctx = ctx, - .request = request, - .list = list_head - }; - fr_dlist_init(&cc->nested, tmpl_cursor_nested_t, entry); - - /* - * Prime the stack! - */ - switch (vpt->type) { - case TMPL_TYPE_ATTR: - _tmpl_pair_cursor_init(list_ctx, cc->list, fr_dlist_head(&vpt->data.attribute.ar), cc); - break; - - case TMPL_TYPE_LIST: - _tmpl_cursor_list_init(list_ctx, cc->list, fr_dlist_head(&vpt->data.attribute.ar), cc); - break; - - default: - fr_assert(0); - break; - } - - /* - * Get the first entry from the tmpl - */ - vp = fr_pair_dcursor_iter_init(cursor, list_head, _tmpl_cursor_next, cc); - if (!vp) { - if (err) { - *err = -1; - if (tmpl_is_list(vpt)) { - fr_strerror_printf("List \"%s\" is empty", vpt->name); - } else { - fr_strerror_printf("No matching \"%s\" pairs found", tmpl_da(vpt)->name); - } - } - return NULL; - } - - return vp; -} - -/** Clear any temporary state allocations - * - */ -void tmpl_pair_cursor_clear(tmpl_pair_cursor_ctx_t *cc) -{ - if (!fr_dlist_num_elements(&cc->nested)) return;/* Help simplify dealing with unused cursor ctxs */ - - fr_dlist_remove(&cc->nested, &cc->leaf); /* Noop if leaf isn't inserted */ - fr_dlist_talloc_free(&cc->nested); - - /* - * Always free the pool because it's allocated when - * any nested ctxs are used. - */ - TALLOC_FREE(cc->pool); -} - /** Copy pairs matching a #tmpl_t in the current #request_t * * @param ctx to allocate new #fr_pair_t in. @@ -1231,7 +799,7 @@ int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tm { fr_pair_t *vp; fr_dcursor_t from; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; TMPL_VERIFY(vpt); @@ -1239,7 +807,7 @@ int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tm fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt)); - for (vp = tmpl_pair_cursor_init(&err, NULL, &cc, &from, request, vpt); + for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt); vp; vp = fr_dcursor_next(&from)) { vp = fr_pair_copy(ctx, vp); @@ -1251,7 +819,7 @@ int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tm } fr_pair_append(out, vp); } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return err; } @@ -1276,7 +844,7 @@ int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *req { fr_pair_t *vp; fr_dcursor_t from; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; TMPL_VERIFY(vpt); @@ -1286,7 +854,7 @@ int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *req fr_pair_list_free(out); - for (vp = tmpl_pair_cursor_init(&err, NULL, &cc, &from, request, vpt); + for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt); vp; vp = fr_dcursor_next(&from)) { switch (vp->da->type) { @@ -1302,7 +870,7 @@ int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *req } } done: - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return err; } @@ -1325,14 +893,14 @@ done: int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt) { fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; fr_pair_t *vp; int err; TMPL_VERIFY(vpt); - vp = tmpl_pair_cursor_init(&err, request, &cc, &cursor, request, vpt); - tmpl_pair_cursor_clear(&cc); + vp = tmpl_dcursor_init(&err, request, &cc, &cursor, request, vpt); + tmpl_dursor_clear(&cc); if (out) *out = vp; @@ -1354,7 +922,7 @@ int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt) int tmpl_find_or_add_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt) { fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; fr_pair_t *vp; int err; @@ -1363,8 +931,8 @@ int tmpl_find_or_add_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt) *out = NULL; - vp = tmpl_pair_cursor_init(&err, NULL, &cc, &cursor, request, vpt); - tmpl_pair_cursor_clear(&cc); + vp = tmpl_dcursor_init(&err, NULL, &cc, &cursor, request, vpt); + tmpl_dursor_clear(&cc); switch (err) { case 0: @@ -1391,287 +959,3 @@ int tmpl_find_or_add_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt) return err; } } - -/** Determines points where the reference list extends beyond the current pair tree - * - * If a particular branch in the VP hierarchy is incomplete, i.e. the chain of attribute - * refers to nodes deeper than the nodes currently in the tree, then we return the - * deepest point node in the tree which matched, and the ar that we failed to evaluate. - * - * If the reference list resolves to one or more structural pairs, return those as well. - * - * This function can be used for a number of different operations, but it's most useful - * for determining insertion points for new attributes, or determining which attributes - * need to be updated. - * - * @param[in] ctx to allocate. It's recommended to pass a pool with space - * for at least five extent structures. - * @param[out] leaf List of extents we discovered by evaluating all - * attribute references. May be NULL. - * @param[out] interior List of extents that need building out, i.e. references - * extend beyond pairs. May be NULL. - * @param[in] request The current #request_t. - * @param[in] vpt specifying the #fr_pair_t type to retrieve or create. - * Must be #TMPL_TYPE_ATTR. - * @return - * - 1 on success a pair was created. - * - 0 on success a pair was found. - * - -1 if a new #fr_pair_t couldn't be found or created. - * - -2 if list could not be found (doesn't exist in current #request_t). - * - -3 if context could not be found (no parent #request_t available). - */ -int tmpl_extents_find(TALLOC_CTX *ctx, - fr_dlist_head_t *leaf, fr_dlist_head_t *interior, - request_t *request, tmpl_t const *vpt) -{ - fr_pair_t *curr = NULL; - fr_pair_list_t *list_head; - - TALLOC_CTX *list_ctx = NULL; - - tmpl_pair_cursor_ctx_t cc; - tmpl_cursor_nested_t *ns = NULL; - - tmpl_request_t *rr = NULL; - tmpl_attr_t const *ar = NULL; - - TMPL_VERIFY(vpt); - - fr_assert(tmpl_is_attr(vpt) || tmpl_is_list(vpt)); - -#define EXTENT_ADD(_out, _ar, _list_ctx, _list) \ - do { \ - tmpl_attr_extent_t *_extent; \ - MEM(_extent = talloc(ctx, tmpl_attr_extent_t)); \ - *_extent = (tmpl_attr_extent_t){ \ - .ar = _ar, \ - .list_ctx = _list_ctx, \ - .list = _list \ - }; \ - fr_dlist_insert_tail(_out, _extent); \ - } while (0) - - /* - * Navigate to the correct request context - */ - while ((rr = fr_dlist_next(&vpt->data.attribute.rr, rr))) { - if (tmpl_request_ptr(&request, rr->request) < 0) { - fr_strerror_printf("Request context \"%s\" not available", - fr_table_str_by_value(tmpl_request_ref_table, rr->request, "")); - return -3; - } - } - - /* - * Get the right list in the specified context - */ - list_head = tmpl_list_head(request, tmpl_list(vpt)); - if (!list_head) { - fr_strerror_printf("List \"%s\" not available in this context", - fr_table_str_by_value(pair_list_table, tmpl_list(vpt), "")); - return -2; - } - list_ctx = tmpl_list_ctx(request, tmpl_list(vpt)); - - /* - * If it's a list, just return the list head - */ - if (vpt->type == TMPL_TYPE_LIST) { - do_list: - if (leaf) EXTENT_ADD(leaf, NULL, list_ctx, list_head); - return 0; - } - - /* - * If it's a leaf skip all the expensive - * initialisation and just return the list - * it's part of. - * - * This is only needed because lists are - * treated specially. Once lists are groups - * this can be removed. - */ - ar = fr_dlist_head(&vpt->data.attribute.ar); - switch (ar->ar_da->type) { - case FR_TYPE_STRUCTURAL: - break; - - default: - goto do_list; - } - - /* - * Initialise the temporary cursor context - */ - cc = (tmpl_pair_cursor_ctx_t){ - .vpt = vpt, - .ctx = ctx, - .request = request, - .list = list_head - }; - fr_dlist_init(&cc.nested, tmpl_cursor_nested_t, entry); - - /* - * Prime the stack! - */ - _tmpl_pair_cursor_init(list_ctx, cc.list, fr_dlist_head(&vpt->data.attribute.ar), &cc); - - /* - * - Continue until there are no evaluation contexts - * - Push a evaluation context if evaluating the head of the - * stack yields a VP and we're not at the deepest attribute - * reference. - * - Return if we have a VP and there are no more attribute - * references to push, i.e. we're at the deepest attribute - * reference. - */ - curr = fr_pair_list_head(list_head); - while ((ns = fr_dlist_tail(&cc.nested))) { - tmpl_attr_t const *n_ar; - - list_ctx = ns->list_ctx; - ar = ns->ar; - curr = _tmpl_cursor_eval(&list_head->order, curr, &cc); - if (!curr) { - /* - * References extend beyond current - * pair tree. - */ - if (!ar->resolve_only && interior) EXTENT_ADD(interior, ar, list_ctx, list_head); - continue; /* Rely on _tmpl_cursor_eval popping the stack */ - } - - /* - * Evaluate the next reference - */ - n_ar = fr_dlist_next(&vpt->data.attribute.ar, ar); - if (n_ar) { - ar = n_ar; - list_head = &curr->vp_group; - list_ctx = curr; /* Allocations are under the group */ - _tmpl_pair_cursor_init(list_ctx, list_head, ar, &cc); - curr = fr_pair_list_head(list_head); - continue; - } - - /* - * VP tree may extend beyond - * the reference. If the reference - * was structural, record this as - * an extent. - */ - switch (ar->da->type) { - case FR_TYPE_STRUCTURAL: - if (leaf) EXTENT_ADD(leaf, NULL, curr, list_head); - continue; - - default: - break; - } - } - - return 0; -} - -/** Allocate interior pairs - * - * Builds out the pair tree to the point where leaf attributes can be added - * - * @param[out] leaf List to add built out attributes to. - * @param[in] interior List to remove attributes from. - * @param[in] vpt We are evaluating. - * @return - * - 0 on success. - * - -1 on failure. - */ -int tmpl_extents_build_to_leaf(fr_dlist_head_t *leaf, fr_dlist_head_t *interior, tmpl_t const *vpt) -{ - tmpl_attr_extent_t *extent = NULL; - - while ((extent = fr_dlist_head(interior))) { - fr_pair_t *vp; - fr_pair_list_t *list; - tmpl_attr_t const *ar; - TALLOC_CTX *list_ctx = extent->list_ctx; - - fr_assert(extent->ar); /* Interior extents MUST contain an ar */ - - /* - * Try and allocate VPs for the - * rest of the attribute references. - */ - for (ar = extent->ar, list = extent->list; - ar; - ar = fr_dlist_next(&vpt->data.attribute.ar, ar)) { - switch (ar->type) { - case TMPL_ATTR_TYPE_NORMAL: - case TMPL_ATTR_TYPE_UNKNOWN: - /* - * Don't build leaf attributes - */ - switch (ar->ar_da->type) { - case FR_TYPE_STRUCTURAL: - break; - - default: - continue; - } - - MEM(vp = fr_pair_afrom_da(list_ctx, ar->ar_da)); /* Copies unknowns */ - fr_pair_append(list, vp); - list = &vp->vp_group; - list_ctx = vp; /* New allocations occur under the VP */ - break; - - default: - fr_assert_fail("references of this type should have been resolved"); - return -1; - } - } - - fr_dlist_remove(interior, extent); /* Do this *before* zeroing the dlist headers */ - *extent = (tmpl_attr_extent_t){ - .list = list, - .list_ctx = list_ctx - }; - fr_dlist_insert_tail(leaf, extent); /* move between in and out */ - } - - return 0; -} - -void tmpl_extents_debug(fr_dlist_head_t *head) -{ - tmpl_attr_extent_t const *extent = NULL; - fr_pair_t *vp = NULL; - - for (extent = fr_dlist_head(head); - extent; - extent = fr_dlist_next(head, extent)) { - tmpl_attr_t const *ar = extent->ar; - char const *ctx_name; - - if (ar) { - FR_FAULT_LOG("extent-interior-attr"); - tmpl_attr_ref_debug(extent->ar, 0); - } else { - FR_FAULT_LOG("extent-leaf"); - } - - ctx_name = talloc_get_name(extent->list_ctx); - if (strcmp(ctx_name, "fr_pair_t") == 0) { - FR_FAULT_LOG("list_ctx : %p (%s, %s)", extent->list_ctx, ctx_name, - ((fr_pair_t *)extent->list_ctx)->da->name); - } else { - FR_FAULT_LOG("list_ctx : %p (%s)", extent->list_ctx, ctx_name); - } - FR_FAULT_LOG("list : %p", extent->list); - if (fr_pair_list_empty(extent->list)) { - FR_FAULT_LOG("list (first) : none (%p)", extent->list); - } else { - vp = fr_pair_list_head(extent->list); - FR_FAULT_LOG("list (first) : %s (%p)", vp->da->name, extent->list); - } - } - -} diff --git a/src/lib/unlang/subrequest.c b/src/lib/unlang/subrequest.c index 5076642bdc..87c4213169 100644 --- a/src/lib/unlang/subrequest.c +++ b/src/lib/unlang/subrequest.c @@ -101,7 +101,7 @@ static unlang_action_t unlang_subrequest_parent_resume(rlm_rcode_t *p_result, re * Find out what we need to build and build it */ if ((tmpl_extents_find(state, &leaf, &interior, request, gext->dst) < 0) || - (tmpl_extents_build_to_leaf(&leaf, &interior, gext->dst) < 0)) { + (tmpl_extents_build_to_leaf_parent(&leaf, &interior, gext->dst) < 0)) { RPDEBUG("Discarding subrequest attributes - Failed allocating groups"); fr_dlist_talloc_free(&leaf); fr_dlist_talloc_free(&interior); diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index cbe7579933..d5ab2e3606 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -31,6 +31,7 @@ RCSID("$Id$") */ #include +#include #include #include @@ -999,7 +1000,7 @@ static xlat_action_t xlat_func_debug_attr(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcur { fr_pair_t *vp; fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; tmpl_t *vpt; fr_value_box_t *attr = fr_dlist_head(in); char const *fmt; @@ -1020,7 +1021,7 @@ static xlat_action_t xlat_func_debug_attr(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcur RIDEBUG("Attributes matching \"%s\"", fmt); RINDENT(); - for (vp = tmpl_pair_cursor_init(NULL, NULL, &cc, &cursor, request, vpt); + for (vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt); vp; vp = fr_dcursor_next(&cursor)) { fr_dict_vendor_t const *vendor; @@ -1105,7 +1106,7 @@ static xlat_action_t xlat_func_debug_attr(UNUSED TALLOC_CTX *ctx, UNUSED fr_dcur talloc_free(dst); } } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); REXDENT(); talloc_free(vpt); @@ -2337,7 +2338,7 @@ static xlat_action_t xlat_func_pairs(TALLOC_CTX *ctx, fr_dcursor_t *out, { tmpl_t *vpt = NULL; fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; fr_value_box_t *vb; fr_value_box_t *in_head = fr_dlist_head(in); @@ -2352,7 +2353,7 @@ static xlat_action_t xlat_func_pairs(TALLOC_CTX *ctx, fr_dcursor_t *out, return XLAT_ACTION_FAIL; } - for (vp = tmpl_pair_cursor_init(NULL, NULL, &cc, &cursor, request, vpt); + for (vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt); vp; vp = fr_dcursor_next(&cursor)) { fr_token_t op = vp->op; @@ -2367,7 +2368,7 @@ static xlat_action_t xlat_func_pairs(TALLOC_CTX *ctx, fr_dcursor_t *out, fr_value_box_bstrdup_buffer_shallow(NULL, vb, NULL, buff, false); fr_dcursor_append(out, vb); } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); talloc_free(vpt); return XLAT_ACTION_DONE; @@ -3384,7 +3385,7 @@ static xlat_action_t protocol_encode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, tmpl_t *vpt; fr_pair_t *vp; fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; bool tainted = false; fr_value_box_t *encoded; @@ -3420,7 +3421,7 @@ static xlat_action_t protocol_encode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, /* * Loop over the attributes, encoding them. */ - for (vp = tmpl_pair_cursor_init(NULL, NULL, &cc, &cursor, request, vpt); + for (vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt); vp != NULL; vp = fr_dcursor_next(&cursor)) { if (vp->da->flags.internal) continue; @@ -3440,7 +3441,7 @@ static xlat_action_t protocol_encode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, len = tp_encode->func(&FR_DBUFF_TMP(p, end), &cursor, encode_ctx); if (len < 0) { RPEDEBUG("Protocol encoding failed"); - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); talloc_free(vpt); return XLAT_ACTION_FAIL; } @@ -3449,7 +3450,7 @@ static xlat_action_t protocol_encode_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, p += len; } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); talloc_free(vpt); /* diff --git a/src/lib/unlang/xlat_eval.c b/src/lib/unlang/xlat_eval.c index eeec8b002d..19015f572e 100644 --- a/src/lib/unlang/xlat_eval.c +++ b/src/lib/unlang/xlat_eval.c @@ -28,8 +28,9 @@ RCSID("$Id$") #include -#include +#include #include +#include #include /* Remove when everything uses new xlat API */ @@ -819,7 +820,7 @@ xlat_eval_pair_real(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *reques fr_value_box_t *value; fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; xlat_action_t ret = XLAT_ACTION_DONE; @@ -831,7 +832,7 @@ xlat_eval_pair_real(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *reques * This allows users to manipulate virtual attributes as if * they were real ones. */ - vp = tmpl_pair_cursor_init(NULL, NULL, &cc, &cursor, request, vpt); + vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt); /* * We didn't find the VP in a list, check to see if it's @@ -902,7 +903,7 @@ xlat_eval_pair_real(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *reques default: /* * The cursor was set to the correct - * position above by tmpl_pair_cursor_init. + * position above by tmpl_dcursor_init. */ vp = fr_dcursor_current(&cursor); /* NULLness checked above */ value = fr_value_box_alloc(ctx, vp->data.type, vp->da, vp->data.tainted); @@ -914,7 +915,7 @@ xlat_eval_pair_real(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *reques } done: - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return ret; } diff --git a/src/lib/util/edit.c b/src/lib/util/edit.c index f7e67198ae..28ce81ed0a 100644 --- a/src/lib/util/edit.c +++ b/src/lib/util/edit.c @@ -596,7 +596,7 @@ fr_edit_list_t *fr_edit_list_alloc(TALLOC_CTX *ctx, int hint) * inserting pairs in a list, then we find the lowest existing pair, * and add pairs there. * - * The functions tmpl_extents_find() and tmpl_extents_build_to_leaf() + * The functions tmpl_extents_find() and tmpl_extents_build_to_leaf_parent() * should help us figure out where the VPs exist or not. * * The overall "update" algorithm is now: diff --git a/src/modules/rlm_expr/rlm_expr.c b/src/modules/rlm_expr/rlm_expr.c index c23c9b292a..974ae8da99 100644 --- a/src/modules/rlm_expr/rlm_expr.c +++ b/src/modules/rlm_expr/rlm_expr.c @@ -26,8 +26,8 @@ RCSID("$Id$") USES_APPLE_DEPRECATED_API #include - #include +#include #include #include @@ -212,7 +212,7 @@ static bool get_number(request_t *request, char const **string, int64_t *answer) ssize_t slen; fr_pair_t *vp; fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; slen = tmpl_afrom_attr_substr(request, NULL, &vpt, &FR_SBUFF_IN(p, strlen(p)), @@ -237,7 +237,7 @@ static bool get_number(request_t *request, char const **string, int64_t *answer) } x = 0; - for (i = 0, vp = tmpl_pair_cursor_init(&err, NULL, &cc, &cursor, request, vpt); + for (i = 0, vp = tmpl_dcursor_init(&err, NULL, &cc, &cursor, request, vpt); (i < max) && (vp != NULL); i++, vp = fr_dcursor_next(&cursor)) { int64_t y; @@ -291,7 +291,7 @@ static bool get_number(request_t *request, char const **string, int64_t *answer) RPEDEBUG("Failed converting &%.*s to an integer value", (int) vpt->len, vpt->name); error: - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return false; } if (value.vb_uint64 > INT64_MAX) { @@ -318,7 +318,7 @@ static bool get_number(request_t *request, char const **string, int64_t *answer) x += y; } /* loop over all found VPs */ - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); if (err != 0) { RWDEBUG("Can't find &%.*s. Using 0 as operand value", (int)vpt->len, vpt->name); diff --git a/src/modules/rlm_linelog/rlm_linelog.c b/src/modules/rlm_linelog/rlm_linelog.c index 9c480dc606..474a63f1bc 100644 --- a/src/modules/rlm_linelog/rlm_linelog.c +++ b/src/modules/rlm_linelog/rlm_linelog.c @@ -26,6 +26,7 @@ RCSID("$Id$") #include #include #include +#include #include #include @@ -561,12 +562,12 @@ build_vector: { #define VECTOR_INCREMENT 20 fr_dcursor_t cursor; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; fr_pair_t *vp; int alloced = VECTOR_INCREMENT, i; MEM(vector = talloc_array(request, struct iovec, alloced)); - for (vp = tmpl_pair_cursor_init(NULL, NULL, &cc, &cursor, request, vpt_p), i = 0; + for (vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt_p), i = 0; vp; vp = fr_dcursor_next(&cursor), i++) { /* need extra for line terminator */ @@ -598,7 +599,7 @@ build_vector: vector[i].iov_len = inst->delimiter_len; } } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); vector_p = vector; vector_len = i; } diff --git a/src/modules/rlm_smtp/rlm_smtp.c b/src/modules/rlm_smtp/rlm_smtp.c index 6dfea892f2..b31900132f 100644 --- a/src/modules/rlm_smtp/rlm_smtp.c +++ b/src/modules/rlm_smtp/rlm_smtp.c @@ -24,11 +24,12 @@ */ RCSID("$Id$") +#include #include +#include #include -#include +#include #include -#include static fr_dict_t const *dict_radius; /*dictionary for radius protocol*/ static fr_dict_t const *dict_freeradius; @@ -219,18 +220,18 @@ static int tmpl_attr_to_slist(fr_mail_ctx_t *uctx, struct curl_slist **out, tmpl { request_t *request = ((fr_mail_ctx_t *)uctx)->request; fr_pair_t *vp; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; int count = 0; /* Iterate over the VP and add the string value to the curl_slist */ - vp = tmpl_pair_cursor_init(NULL, NULL, &cc, &uctx->cursor, request, tmpl); + vp = tmpl_dcursor_init(NULL, NULL, &cc, &uctx->cursor, request, tmpl); while (vp) { count += 1; *out = curl_slist_append(*out, vp->vp_strvalue); vp = fr_dcursor_next(&uctx->cursor); } /* Return the number of elements that were found */ - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return count; } @@ -267,12 +268,12 @@ static int tmpl_arr_to_slist (rlm_smtp_thread_t *t, fr_mail_ctx_t *uctx, struct static ssize_t tmpl_attr_to_sbuff (fr_mail_ctx_t *uctx, fr_sbuff_t *out, tmpl_t const *vpt, char const *delimeter) { fr_pair_t *vp; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; ssize_t copied = 0; /* Loop through the elements to be added to the sbuff */ - vp = tmpl_pair_cursor_init(NULL, NULL, &cc, &uctx->cursor, uctx->request, vpt); + vp = tmpl_dcursor_init(NULL, NULL, &cc, &uctx->cursor, uctx->request, vpt); while (vp) { copied += fr_sbuff_in_bstrncpy(out, vp->vp_strvalue, vp->vp_length); vp = fr_dcursor_next(&uctx->cursor); @@ -281,7 +282,7 @@ static ssize_t tmpl_attr_to_sbuff (fr_mail_ctx_t *uctx, fr_sbuff_t *out, tmpl_t copied += fr_sbuff_in_strcpy(out, delimeter); } } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return copied; } @@ -377,11 +378,11 @@ static int tmpl_attr_to_attachment (fr_mail_ctx_t *uctx, curl_mime *mime, const { fr_pair_t *vp; request_t *request = uctx->request; - tmpl_pair_cursor_ctx_t cc; + tmpl_dcursor_ctx_t cc; int attachments_set = 0; /* Check for any file attachments */ - for( vp = tmpl_pair_cursor_init(NULL, NULL, &cc, &uctx->cursor, request, tmpl); + for( vp = tmpl_dcursor_init(NULL, NULL, &cc, &uctx->cursor, request, tmpl); vp; vp = fr_dcursor_next(&uctx->cursor)){ if(vp->vp_tainted) { @@ -390,7 +391,7 @@ static int tmpl_attr_to_attachment (fr_mail_ctx_t *uctx, curl_mime *mime, const } attachments_set += str_to_attachments(uctx, mime, vp->vp_strvalue, vp->vp_length, path_buffer, m); } - tmpl_pair_cursor_clear(&cc); + tmpl_dursor_clear(&cc); return attachments_set; }