typedef int (*xlat_thread_instantiate_t)(void *xlat_inst, void *xlat_thread_inst,
xlat_exp_t const *exp, void *uctx);
+/** xlat detach callback
+ *
+ * Is called whenever an xlat_node_t is freed.
+ *
+ * Detach should close all handles associated with the xlat instance, and
+ * free any memory allocated during instantiate.
+ *
+ * @param[in] instance to free.
+ * @return
+ * - 0 on success.
+ * - -1 if detach failed.
+ */
+typedef int (*xlat_detach_t)(void *xlat_inst, void *uctx);
+
+/** xlat thread detach callback
+ *
+ * Is called whenever an xlat_node_t is freed (if ephemeral),
+ * or when a thread exits.
+ *
+ * Detach should close all handles associated with the xlat instance, and
+ * free any memory allocated during instantiate.
+ *
+ * @param[in] instance to free.
+ * @return
+ * - 0 on success.
+ * - -1 if detach failed.
+ */
+typedef int (*xlat_thread_detach_t)(void *xlat_thread_inst, void *uctx);
+
xlat_action_t xlat_frame_eval_repeat(TALLOC_CTX *ctx, fr_cursor_t *out,
xlat_exp_t const **child, bool *alternate,
REQUEST *request, xlat_exp_t const **in,
int xlat_async_register(TALLOC_CTX *ctx,
char const *name, xlat_func_async_t func,
xlat_instantiate_t instantiate, size_t inst_size,
+ xlat_detach_t detach,
xlat_thread_instantiate_t thread_instantiate, size_t thread_inst_size,
+ xlat_thread_detach_t thread_detach,
void *uctx);
void xlat_unregister(char const *name);
int xlat_init(void);
void xlat_free(void);
+/*
+ * xlat_inst.c
+ */
+int xlat_thread_instantiate(void);
+
+int xlat_instatiate_request(xlat_exp_t *root);
+
+int xlat_instantiate(xlat_exp_t *root);
+
+int xlat_inst_init(void);
+
+void xlat_inst_free(void);
+
#ifdef __cplusplus
}
#endif
unlang_op.c \
xlat_eval.c \
xlat_func.c \
+ xlat_inst.c \
xlat_tokenize.c
# This lets the linker determine which version of the SSLeay functions to use.
#include <freeradius-devel/rad_assert.h>
#include <ctype.h>
-#include "xlat.h"
+#include "xlat_priv.h"
FR_NAME_NUMBER const xlat_action_table[] = {
{ "push-child", XLAT_ACTION_PUSH_CHILD },
static size_t xlat_process(TALLOC_CTX *ctx, char **out, REQUEST *request, xlat_exp_t const * const head,
xlat_escape_t escape, void const *escape_ctx);
-
/** One letter expansions
*
* @param[in] ctx to allocate boxed value, and buffers in.
{
xlat_action_t action;
- /* Fixme - Pass in instance and thread instance */
- action = node->xlat->func.async(ctx, out, request, NULL, NULL, result);
+ /* Fixme - We should always have node->inst and node->thread_inst */
+ action = node->xlat->func.async(ctx, out, request,
+ node->inst ? node->inst->data : NULL,
+ node->thread_inst ? node->thread_inst->data : NULL, result);
switch (action) {
case XLAT_ACTION_PUSH_CHILD:
case XLAT_ACTION_YIELD:
*out = NULL;
return _xlat_eval_compiled(ctx, out, 0, request, xlat, escape, escape_ctx);
}
+
+/** Walk over all xlat nodes (depth first) in a xlat expansion, calling a callback
+ *
+ * @param[in] exp to evaluate.
+ * @param[in] walker callback to pass nodes to.
+ * @param[in] type if > 0 a mask of types to call walker for.
+ * @param[in] uctx to pass to walker.
+ * @return
+ * - 0 on success (walker always returned 0).
+ * - <0 if walker returned <0.
+ */
+int xlat_eval_walk(xlat_exp_t *exp, xlat_walker_t walker, xlat_state_t type, void *uctx)
+{
+ xlat_exp_t *node;
+ int ret;
+
+ /*
+ * Iterate over nodes at the same depth
+ */
+ for (node = exp; node; node = node->next) {
+ switch (node->type){
+ case XLAT_FUNC:
+ if (!type || (type & XLAT_FUNC)) {
+ ret = walker(node, uctx);
+ if (ret < 0) return ret;
+ }
+
+ /*
+ * Now evaluate the function's arguments
+ */
+ if (node->child) {
+ ret = xlat_eval_walk(node->child, walker, type, uctx);
+ if (ret < 0) return ret;
+ }
+ break;
+
+ case XLAT_ALTERNATE:
+ if (!type || (type & XLAT_ALTERNATE)) {
+ ret = walker(node, uctx);
+ if (ret < 0) return ret;
+ }
+
+ /*
+ * Evaluate the alternate expansion path
+ */
+ ret = xlat_eval_walk(node->alternate, walker, type, uctx);
+ if (ret < 0) return ret;
+ break;
+
+ default:
+ if (!type || (type & node->type)) {
+ ret = walker(node, uctx);
+ if (ret < 0) return ret;
+ }
+ }
+ }
+
+ return 0;
+}
#include <freeradius-devel/base64.h>
#include <ctype.h>
-#include "xlat.h"
+#include "xlat_priv.h"
static rbtree_t *xlat_root = NULL;
/*
* find the appropriate registered xlat function.
*/
-xlat_t *xlat_find(char const *name)
+xlat_t *xlat_func_find(char const *name)
{
xlat_t find;
xlat_t *found;
* @param[in] inst_size The size of the instance struct.
* Pre-allocated for use by the instantiate function.
* If 0, no memory will be allocated.
+ * @param[in] detach Called when an xlat_exp_t is freed.
* @param[in] thread_instantiate thread_instantiation_function. Called whenever a
* a thread is started to create thread local instance
* data.
* @param[in] thread_inst_size The size of the thread instance struct.
* Pre-allocated for use by the thread instance function.
* If 0, no memory will be allocated.
+ * @param[in] thread_detach Called when an xlat_exp_t is freed (if ephemeral),
+ * or when a thread exits.
* @param[in] uctx To pass to instantiate callbacks and the xlat function
* when it's called. Usually the module instance that
* registered the xlat.
int xlat_async_register(TALLOC_CTX *ctx,
char const *name, xlat_func_async_t func,
xlat_instantiate_t instantiate, size_t inst_size,
+ xlat_detach_t detach,
xlat_thread_instantiate_t thread_instantiate, size_t thread_inst_size,
+ xlat_thread_detach_t thread_detach,
void *uctx)
{
xlat_t *c;
c->func.async = func;
c->type = XLAT_FUNC_ASYNC;
+
c->instantiate = instantiate;
c->thread_instantiate = thread_instantiate;
+
c->inst_size = inst_size;
c->thread_inst_size = thread_inst_size;
+
+ c->detach = detach;
+ c->thread_detach = thread_detach;
+
c->async_safe = false; /* async safe in this case means it might yield */
c->uctx = uctx;
name = cf_pair_attr(cf_item_to_pair(ci));
rad_assert(name != NULL);
- xlat = xlat_find(name);
+ xlat = xlat_func_find(name);
if (!xlat) continue;
if (xlat->buf_len > 0) {
name = cf_pair_attr(cf_item_to_pair(found));
rad_assert(name != NULL);
- xlat = xlat_find(name);
+ xlat = xlat_func_find(name);
if (!xlat) return -1;
if (xlat->buf_len > 0) {
name = cf_pair_attr(cf_item_to_pair(ci));
rad_assert(name != NULL);
- xlat = xlat_find(name);
+ xlat = xlat_func_find(name);
if (xlat) {
ssize_t rcode;
name1 = cf_section_name1(cs);
name2 = cf_section_name2(cs);
- if (xlat_find(name2)) {
+ if (xlat_func_find(name2)) {
cf_log_err(cs, "An expansion is already registered for this name");
return -1;
}
* This is ok, it just means the module
* doesn't have an xlat method.
*/
- if (!xlat_find(attr)) {
+ if (!xlat_func_find(attr)) {
talloc_free(xr);
return 1;
}
#ifdef WITH_UNLANG
for (i = 0; xlat_foreach_names[i] != NULL; i++) {
xlat_register(&xlat_foreach_inst[i], xlat_foreach_names[i], xlat_foreach, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, true);
- c = xlat_find(xlat_foreach_names[i]);
+ c = xlat_func_find(xlat_foreach_names[i]);
rad_assert(c != NULL);
c->internal = true;
}
#endif
#define XLAT_REGISTER(_x) xlat_register(NULL, STRINGIFY(_x), xlat_ ## _x, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, true); \
- c = xlat_find(STRINGIFY(_x)); \
+ c = xlat_func_find(STRINGIFY(_x)); \
rad_assert(c != NULL); \
c->internal = true
#endif
xlat_register(&xlat_foreach_inst[0], "debug", xlat_debug, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN, true);
- c = xlat_find("debug");
+ c = xlat_func_find("debug");
rad_assert(c != NULL);
c->internal = true;
--- /dev/null
+/*
+ * 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$
+ *
+ * @file xlat_inst.c
+ * @brief Create instance data for xlat function calls.
+ *
+ * @copyright 2018 The FreeRADIUS server project
+ * @copyright 2018 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+
+#include <ctype.h>
+
+#include "xlat_priv.h"
+
+/** Holds instance data created by xlat_instantiate
+ */
+static rbtree_t *xlat_inst_tree;
+
+/** Holds thread specific instance data created by xlat_instantiate
+ */
+fr_thread_local_setup(rbtree_t *, xlat_thread_inst_tree)
+
+/** Destructor for xlat_inst_t
+ *
+ * Calls detach method if provided by xlat expansion
+ *
+ * @note This cannot be converted to a talloc destructor,
+ * as we need to call thread_detach *before* any of the children
+ * of the talloc ctx are freed.
+ */
+static int _xlat_inst_free(xlat_inst_t *inst)
+{
+ rad_assert(inst->node->type == XLAT_FUNC);
+
+ /*
+ * Remove permanent data from the instance tree.
+ */
+ if (!inst->node->ephemeral) rbtree_deletebydata(xlat_inst_tree, inst);
+
+ if (inst->node->xlat->detach) (void) inst->node->xlat->detach(inst->data, inst->node->xlat->uctx);
+
+ return 0;
+}
+
+/** Compare two xlat instances based on node pointer
+ *
+ * @param[in] a First xlat expansion instance.
+ * @param[in] b Second xlat expansion instance.
+ * @return
+ * - +1 if a > b.
+ * - -1 if a < b.
+ * - 0 if a == b.
+ */
+static int _xlat_inst_cmp(void const *a, void const *b)
+{
+ xlat_thread_inst_t const *my_a = a, *my_b = b;
+
+ return (my_a->node > my_b->node) - (my_a->node < my_b->node);
+}
+
+/** Compare two thread instances based on node pointer
+ *
+ * @param[in] a First thread specific xlat expansion instance.
+ * @param[in] b Second thread specific xlat expansion instance.
+ * @return
+ * - +1 if a > b.
+ * - -1 if a < b.
+ * - 0 if a == b.
+ */
+static int _xlat_thread_inst_cmp(void const *a, void const *b)
+{
+ xlat_thread_inst_t const *my_a = a, *my_b = b;
+
+ return (my_a->node > my_b->node) - (my_a->node < my_b->node);
+}
+
+/** Destructor for xlat_thread_inst_t
+ *
+ * Calls thread_detach method if provided by xlat expansion
+ *
+ * @note This cannot be converted to a talloc destructor,
+ * as we need to call thread_detach *before* any of the children
+ * of the talloc ctx are freed.
+ */
+static void _xlat_thread_inst_free(void *to_free)
+{
+ xlat_thread_inst_t *thread_inst = talloc_get_type_abort(to_free, xlat_thread_inst_t);
+
+ rad_assert(thread_inst->node->type == XLAT_FUNC);
+
+ if (thread_inst->node->xlat->thread_detach) {
+ (void) thread_inst->node->xlat->thread_detach(thread_inst->data, thread_inst->node->xlat->uctx);
+ }
+
+ talloc_free(thread_inst);
+}
+
+/** Frees the thread local instance free and any thread local instance data
+ *
+ * @param[in] to_free Thread specific module instance tree to free.
+ */
+static void _xlat_thread_inst_tree_free(void *to_free)
+{
+ rbtree_t *thread_inst_tree = talloc_get_type_abort(to_free , rbtree_t);
+
+ talloc_free(thread_inst_tree);
+}
+
+/** Create thread instances where needed
+ *
+ * @param[in] node to perform thread instantiation for.
+ * @return
+ * - 0 on success. The node/thread specific data will be inserted
+ * into xlat_thread_inst_tree.
+ * - -1 on failure.
+ */
+static xlat_thread_inst_t *xlat_thread_inst_alloc(xlat_exp_t *node)
+{
+ xlat_thread_inst_t *thread_inst = NULL;
+ int ret;
+
+ (void)talloc_get_type_abort(node, xlat_exp_t);
+
+ MEM(thread_inst = talloc_zero(NULL, xlat_thread_inst_t));
+ thread_inst->node = node;
+
+ rad_assert(node->type == XLAT_FUNC);
+ rad_assert(!node->thread_inst); /* May be missing inst, but this is OK */
+
+ if (node->xlat->thread_inst_size) {
+ MEM(thread_inst->data = talloc_zero_array(thread_inst, uint8_t, node->xlat->thread_inst_size));
+
+ /*
+ * This is expensive, only do it if we might
+ * might be using it.
+ */
+#ifndef TALLOC_GET_TYPE_ABORT_NOOP
+ talloc_set_name(thread_inst, "%s_thread_inst_t", node->xlat->name);
+#endif
+ }
+
+ if (node->xlat->thread_instantiate) {
+ ret = node->xlat->thread_instantiate(node->inst, thread_inst->data, node, node->xlat->uctx);
+ if (ret < 0) {
+ talloc_free(thread_inst);
+ return NULL;
+ }
+ }
+
+ return thread_inst;
+}
+
+/** Walker callback for xlat_inst_tree
+ *
+ */
+static int _xlat_thread_instantiate(UNUSED void *ctx, void *data)
+{
+ xlat_thread_inst_t *thread_inst;
+
+ thread_inst = xlat_thread_inst_alloc(data);
+ if (!thread_inst) return -1;
+
+ rbtree_insert(xlat_thread_inst_tree, thread_inst);
+
+ return 0;
+}
+
+/** Create thread specific instance tree and create thread instances
+ *
+ * This should be called directly after the module_thread_instantiate function.
+ *
+ * Memory will be freed automatically when the thread exits.
+ */
+int xlat_thread_instantiate(void)
+{
+ int ret;
+
+ if (!xlat_thread_inst_tree) {
+ MEM(xlat_thread_inst_tree = rbtree_create(NULL, _xlat_thread_inst_cmp, _xlat_thread_inst_free, 0));
+ fr_thread_local_set_destructor(xlat_thread_inst_tree,
+ _xlat_thread_inst_tree_free, xlat_thread_inst_tree);
+ }
+
+ /*
+ * Walk the inst tree, creating thread
+ * specific instances.
+ */
+ ret = rbtree_walk(xlat_inst_tree, RBTREE_PRE_ORDER, _xlat_thread_instantiate, NULL);
+ if (ret < 0) {
+ TALLOC_FREE(xlat_thread_inst_tree); /* Destroy the thread_inst_tree if instantiation fails */
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Allocate instance data for an xlat expansion
+ *
+ * @param[in] node to allocate instance data for.
+ */
+static xlat_inst_t *xlat_inst_alloc(xlat_exp_t *node)
+{
+ xlat_inst_t *inst = NULL;
+
+ rad_assert(xlat_inst_tree); /* xlat_inst_init must have been called */
+ rad_assert(node->type == XLAT_FUNC);
+ rad_assert(!node->inst);
+
+ /*
+ * Instance data is freed when the
+ * node is freed.
+ */
+ MEM(inst = talloc_zero(node, xlat_inst_t));
+ talloc_set_destructor(inst, _xlat_inst_free);
+
+ if (node->xlat->inst_size) {
+ MEM(inst->data = talloc_zero_array(inst, uint8_t, node->xlat->inst_size));
+
+ /*
+ * This is expensive, only do it if we might
+ * might be using it.
+ */
+#ifndef TALLOC_GET_TYPE_ABORT_NOOP
+ talloc_set_name(inst, "%s_inst_t", node->xlat->name);
+#endif
+ }
+
+ if (node->xlat->instantiate) {
+ int ret;
+
+ ret = node->xlat->instantiate(inst->data, node, node->xlat->uctx);
+ if (ret < 0) {
+ talloc_free(inst);
+ return NULL;
+ }
+ }
+
+ return inst;
+}
+
+/** Callback for creating "ephemeral" instance data for a #xlat_exp_t
+ *
+ * @param[in] node to create "ephemeral" instance data for.
+ * @param[in] uctx UNUSED.
+ * @return
+ * - 0 if instantiation functions were successful.
+ * - -1 if either instantiation function failed.
+ */
+static int _xlat_instantiate_request_walker(xlat_exp_t *node, UNUSED void *uctx)
+{
+ rad_assert(!node->inst && !node->thread_inst);
+
+ node->inst = xlat_inst_alloc(node);
+ if (!node->inst) return -1;
+
+ node->thread_inst = xlat_thread_inst_alloc(node);
+ if (!node->thread_inst) {
+ TALLOC_FREE(node->inst);
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Create instance data for "ephemeral" xlats
+ *
+ * @node This must only be used for xlats created at runtime.
+ *
+ * @param[in] root of xlat tree to create instance data for.
+ */
+int xlat_instatiate_request(xlat_exp_t *root)
+{
+ return xlat_eval_walk(root, _xlat_instantiate_request_walker, XLAT_FUNC, NULL);
+}
+
+/** Callback for creating "permanent" instance data for a #xlat_exp_t
+ *
+ * @param[in] node to create "permanent" instance data for.
+ * @param[in] uctx UNUSED.
+ * @return
+ * - 0 if instantiation functions were successful.
+ * - -1 if either instantiation function failed.
+ */
+static int _xlat_instantiate_walker(xlat_exp_t *node, UNUSED void *uctx)
+{
+ xlat_thread_inst_t *thread_inst;
+ bool ret;
+
+ rad_assert(!node->inst && !node->thread_inst);
+
+ node->inst = xlat_inst_alloc(node);
+ if (!node->inst) return -1;
+
+ thread_inst = xlat_thread_inst_alloc(node);
+ if (!thread_inst) {
+ TALLOC_FREE(node->inst);
+ return -1;
+ }
+
+ ret = rbtree_insert(xlat_inst_tree, node->inst);
+ if (!fr_cond_assert(ret)) {
+ insert_error:
+ TALLOC_FREE(node->inst);
+ talloc_free(thread_inst);
+ return -1;
+ }
+
+ ret = rbtree_insert(xlat_thread_inst_tree, thread_inst);
+ if (!ret) goto insert_error;
+
+ return 0;
+}
+
+/** Create instance data for "permanent" xlats
+ *
+ * @note This must only be used for xlats created during startup.
+ * IF THIS IS CALLED FOR XLATS TOKENIZED AT RUNTIME YOU WILL LEAK LARGE AMOUNTS OF MEMORY.
+ * USE #xlat_instantiate_request INSTEAD.
+ *
+ * @param[in] root of xlat tree to create instance data for.
+ */
+int xlat_instantiate(xlat_exp_t *root)
+{
+ return xlat_eval_walk(root, _xlat_instantiate_walker, XLAT_FUNC, NULL);
+}
+
+/** Initialise the xlat inst code
+ *
+ * Call xlat_inst_free when done.
+ */
+int xlat_inst_init(void)
+{
+ if (xlat_inst_tree) return 0;
+
+ xlat_inst_tree = rbtree_create(NULL, _xlat_inst_cmp, NULL, RBTREE_FLAG_NONE);
+ if (!xlat_inst_tree) return -1;
+
+ return 0;
+}
+
+/** Free the main xlat instance tree
+ *
+ * @note Will not free thread/expansion specific data. This will be freed as threads
+ * exit.
+ */
+void xlat_inst_free(void)
+{
+ /*
+ * All xlat_exp_t should have been freed
+ * before xlat_inst_free is called.
+ */
+ rad_assert(rbtree_num_elements(xlat_inst_tree) == 0);
+ talloc_free(xlat_inst_tree);
+}
/**
* $Id$
*
- * @file main/xlat.h
+ * @file main/xlat_priv.h
* @brief String expansion ("translation"). Implements %Attribute -> value
*
* Private structures for the xlat tokenizer and xlat eval code.
* @copyright 2000,2006 The FreeRADIUS server project
* @copyright 2000 Alan DeKok <aland@ox.org>
*/
+#ifndef _FR_XLAT_PRIV_H
+#define _FR_XLAT_PRIV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
#ifdef DEBUG_XLAT
# define XLAT_DEBUG RDEBUG3
xlat_instantiate_t instantiate; //!< Instantiation function.
xlat_thread_instantiate_t thread_instantiate; //!< Thread instantiation function.
+ xlat_detach_t detach; //!< Destructor for when xlat instances are freed.
+ xlat_thread_detach_t thread_detach; //!< Destructor for when xlat thread instance data
+ ///< is freed.
+
bool internal; //!< If true, cannot be redefined.
size_t inst_size; //!< Size of instance data to pre-allocate.
xlat_escape_t escape; //!< Escape function to apply to dynamic input to func.
} xlat_t;
+
typedef enum {
- XLAT_LITERAL, //!< Literal string
- XLAT_ONE_LETTER, //!< Literal string with %v
- XLAT_FUNC, //!< xlat module
- XLAT_VIRTUAL, //!< virtual attribute
- XLAT_ATTRIBUTE, //!< xlat attribute
+ XLAT_LITERAL = 0x01, //!< Literal string
+ XLAT_ONE_LETTER = 0x02, //!< Literal string with %v
+ XLAT_FUNC = 0x04, //!< xlat module
+ XLAT_VIRTUAL = 0x08, //!< virtual attribute
+ XLAT_ATTRIBUTE = 0x10, //!< xlat attribute
#ifdef HAVE_REGEX
- XLAT_REGEX, //!< regex reference
+ XLAT_REGEX = 0x11, //!< regex reference
#endif
- XLAT_ALTERNATE //!< xlat conditional syntax :-
+ XLAT_ALTERNATE = 0x12 //!< xlat conditional syntax :-
} xlat_state_t;
+
+/** Instance data for an xlat expansion node
+ *
+ */
+typedef struct {
+ xlat_exp_t *node; //!< Node this data relates to.
+ void *data; //!< xlat node specific instance data.
+} xlat_inst_t;
+
+/** Thread specific instance data for xlat expansion node
+ *
+ */
+typedef struct {
+ xlat_exp_t *node; //!< Node this data relates to.
+ void *data; //!< Thread specific instance data.
+
+ uint64_t total_calls; //! total number of times we've been called
+ uint64_t active_callers; //! number of active callers. i.e. number of current yields
+} xlat_thread_inst_t;
+
+/** An xlat expansion node
+ *
+ * These nodes form a tree which represents one or more nested expansions.
+ */
struct xlat_exp {
- char const *fmt; //!< The format string.
+ char const *fmt; //!< The original format string.
size_t len; //!< Length of the format string.
bool async_safe; //!< carried from all of the children
int regex_index; //!< for %{1} and friends.
};
- xlat_t const *xlat; //!< The xlat expansion to expand format with.
+
+ /*
+ * An xlat function
+ */
+ struct {
+ xlat_t const *xlat; //!< The xlat expansion to expand format with.
+ bool ephemeral; //!< Instance data is ephemeral (not inserted)
+ ///< into the instance tree.
+ xlat_inst_t *inst; //!< Instance data for the #xlat_t.
+ xlat_thread_inst_t *thread_inst; //!< Thread specific instance.
+ ///< ONLY USED FOR EPHEMERAL XLATS.
+ };
};
typedef struct xlat_out {
size_t len; //!< Length of the output string.
} xlat_out_t;
+/** Walker callback for xlat_walk()
+ *
+ * @param[in] exp being evaluated.
+ * @param[in] uctx passed to xlat_walk.
+ * @return
+ * - 0 on success.
+ * - <0 if node evaluation failed. Causes xlat_walk to return the negative integer.
+ */
+typedef int (*xlat_walker_t)(xlat_exp_t *exp, void *uctx);
+
+/*
+ * xlat_tokenize.c
+ */
+ssize_t xlat_tokenize_request(TALLOC_CTX *ctx, REQUEST *request, char const *fmt, xlat_exp_t **head);
+
+/*
+ * xlat_func.c
+ */
+xlat_t *xlat_func_find(char const *name);
-ssize_t xlat_tokenize_request(TALLOC_CTX *ctx, REQUEST *request, char const *fmt, xlat_exp_t **head);
+/*
+ * xlat_eval.c
+ */
+int xlat_eval_walk(xlat_exp_t *exp, xlat_walker_t walker, xlat_state_t type, void *uctx);
-xlat_t *xlat_find(char const *name);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
#include <freeradius-devel/rad_assert.h>
#include <ctype.h>
-#include "xlat.h"
+#include "xlat_priv.h"
#undef XLAT_DEBUG
#ifdef DEBUG_XLAT
*/
if (*q == ':') {
*q = '\0';
- node->xlat = xlat_find(node->fmt);
+ node->xlat = xlat_func_find(node->fmt);
if (node->xlat) {
/*
* %{mod:foo}
* Might be a virtual XLAT attribute
*/
if (node->attr->type == TMPL_TYPE_ATTR_UNDEFINED) {
- node->xlat = xlat_find(node->attr->tmpl_unknown_name);
+ node->xlat = xlat_func_find(node->attr->tmpl_unknown_name);
if (node->xlat && node->xlat->mod_inst && !node->xlat->internal) {
talloc_free(node);
*error = "Missing content in expansion";