void const *mod_inst, void const *xlat_inst,
REQUEST *request, char const *fmt);
+/** Async xlat callback function
+ *
+ * Ingests a list of value boxes as arguments, with arguments delimited by spaces.
+ *
+ * @param[in] ctx to allocate any fr_value_box_t in.
+ * @param[out] out Where to append #fr_value_box_t containing the output of this function.
+ * @param[in] xlat_inst Global xlat instance.
+ * @param[in] xlat_thread_inst Thread specific xlat instance.
+ * @param[in] request The current request.
+ * @param[in] in Input arguments.
+ * @return
+ * - XLAT_ACTION_YIELD xlat function is waiting on an I/O event and
+ * has pushed a resumption function onto the stack.
+ * - XLAT_ACTION_DONE xlat function completed. This does not necessarily
+ * mean it turned a result.
+ * - XLAT_ACTION_FAIL the xlat function failed.
+ */
+typedef xlat_action_t (*xlat_func_async_t)(TALLOC_CTX *ctx, fr_cursor_t *out,
+ void const *xlat_inst, void *xlat_thread_inst,
+ REQUEST *request, fr_value_box_t const *in,
+ void *uctx);
+
/** Allocate new instance data for an xlat instance
*
- * @param[out] xlat_inst Structure to populate. Allocated by #map_proc_instantiate.
- * @param[in] mod_inst Module instance that registered the #xlat_func_t.
- * @param[in] fmt string to base instantiation around.
+ * @param[out] xlat_inst Structure to populate. Allocated by #map_proc_instantiate.
+ * @param[in] exp Tokenized expression to use in expansion.
+ * @param[in] uctx passed to the registration function.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+typedef int (*xlat_instantiate_t)(void *xlat_inst, xlat_exp_t const *exp, void *uctx);
+
+/** Allocate new tread instance data for an xlat instance
+ *
+ * @param[in] xlat_inst Previously instantiated xlat instance.
+ * @param[out] xlat_thread_inst Thread specific structure to populate.
+ * Allocated by #map_proc_instantiate.
+ * @param[in] exp Tokenized expression to use in expansion.
+ * @param[in] uctx passed to the registration function.
* @return
* - 0 on success.
* - -1 on failure.
*/
-typedef int (*xlat_instantiate_t)(void *xlat_inst, void *mod_inst, char const *fmt);
+typedef int (*xlat_thread_instantiate_t)(void *xlat_inst, void *xlat_thread_inst,
+ xlat_exp_t const *exp, 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,
- fr_value_box_t *result);
+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,
+ fr_value_box_t *result);
-xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_cursor_t *out, xlat_exp_t const **child,
- REQUEST *request, xlat_exp_t const **in);
+xlat_action_t xlat_frame_eval(TALLOC_CTX *ctx, fr_cursor_t *out, xlat_exp_t const **child,
+ REQUEST *request, xlat_exp_t const **in);
-ssize_t xlat_eval(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape,
- void const *escape_ctx)
- CC_HINT(nonnull (1 ,3 ,4));
+ssize_t xlat_eval(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape,
+ void const *escape_ctx)
+ CC_HINT(nonnull (1 ,3 ,4));
-ssize_t xlat_eval_compiled(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat,
- xlat_escape_t escape, void const *escape_ctx)
- CC_HINT(nonnull (1 ,3 ,4));
+ssize_t xlat_eval_compiled(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat,
+ xlat_escape_t escape, void const *escape_ctx)
+ CC_HINT(nonnull (1 ,3 ,4));
-ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, REQUEST *request,
- char const *fmt, xlat_escape_t escape, void const *escape_ctx)
- CC_HINT(nonnull (2, 3, 4));
+ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, REQUEST *request,
+ char const *fmt, xlat_escape_t escape, void const *escape_ctx)
+ CC_HINT(nonnull (2, 3, 4));
-ssize_t xlat_aeval_compiled(TALLOC_CTX *ctx, char **out, REQUEST *request,
- xlat_exp_t const *xlat, xlat_escape_t escape, void const *escape_ctx)
- CC_HINT(nonnull (2, 3, 4));
+ssize_t xlat_aeval_compiled(TALLOC_CTX *ctx, char **out, REQUEST *request,
+ xlat_exp_t const *xlat, xlat_escape_t escape, void const *escape_ctx)
+ CC_HINT(nonnull (2, 3, 4));
-ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error);
+ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error);
-size_t xlat_snprint(char *buffer, size_t bufsize, xlat_exp_t const *node);
+size_t xlat_snprint(char *buffer, size_t bufsize, xlat_exp_t const *node);
#define XLAT_DEFAULT_BUF_LEN 2048
xlat_instantiate_t instantiate, size_t inst_size,
size_t buf_len, bool async_safe);
-void xlat_unregister(void *mod_inst, char const *name, xlat_func_t func);
+int xlat_async_register(TALLOC_CTX *ctx,
+ char const *name, xlat_func_t func,
+ xlat_instantiate_t instantiate, size_t inst_size,
+ xlat_thread_instantiate_t thread_instantiate, size_t thread_inst_size,
+ void *uctx);
+
+void xlat_unregister(char const *name);
void xlat_unregister_module(void *instance);
int xlat_register_redundant(CONF_SECTION *cs);
int xlat_init(void);
* Remove all xlat's registered to module instance.
*/
if (mod_inst->dl_inst && mod_inst->dl_inst->data) {
- xlat_unregister(mod_inst->dl_inst->data, mod_inst->name, NULL);
+ xlat_unregister(mod_inst->name);
/*
* Remove any registered paircompares.
*/
talloc_free(request);
talloc_free(state);
- xlat_unregister(NULL, "poke", xlat_poke);
+ xlat_unregister("poke");
/*
* Free the event list.
# define XLAT_DEBUG(...)
#endif
+/** Function types
+ *
+ */
+typedef enum {
+ XLAT_FUNC_STRING, //!< Ingests and excretes strings.
+ XLAT_FUNC_BOXED //!< Ingests and excretes value boxes.
+} xlat_func_type_t;
+
typedef struct xlat_t {
- char name[FR_MAX_STRING_LEN]; //!< Name of the xlat expansion.
- int length; //!< Length of name.
- void *mod_inst; //!< Module instance passed to xlat and escape functions.
- xlat_func_t func; //!< xlat function.
- xlat_escape_t escape; //!< Escape function to apply to dynamic input to func.
- xlat_instantiate_t instantiate; //!< Instantiation function.
- size_t inst_size; //!< Length of instance data to pre-allocate.
- size_t buf_len; //!< Length of output buffer to pre-allocate.
- bool internal; //!< If true, cannot be redefined.
- bool async_safe; ///!< If true, is async safe
+ char const *name; //!< Name of xlat function.
+ xlat_func_t func; //!< xlat function.
+ xlat_func_type_t type; //!< Type of xlat function.
+
+ xlat_instantiate_t instantiate; //!< Instantiation function.
+ xlat_thread_instantiate_t thread_instantiate; //!< Thread instantiation function.
+
+ bool internal; //!< If true, cannot be redefined.
+
+ size_t inst_size; //!< Size of instance data to pre-allocate.
+ size_t thread_inst_size; //!< Size of the thread instance data to pre-allocate.
+
+ bool async_safe; //!< If true, is async safe
+ void *uctx; //!< uctx to pass to instantiation functions.
+
+ size_t buf_len; //!< Length of output buffer to pre-allocate.
+ void *mod_inst; //!< Module instance passed to xlat
+ 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_ONE_LETTER, //!< Literal string with %v
XLAT_FUNC, //!< xlat module
XLAT_VIRTUAL, //!< virtual attribute
XLAT_ATTRIBUTE, //!< xlat attribute
static int xlat_cmp(void const *one, void const *two)
{
xlat_t const *a = one, *b = two;
+ size_t a_len, b_len;
int ret;
- ret = (a->length > b->length) - (a->length < b->length);
+ a_len = strlen(a->name);
+ b_len = strlen(b->name);
+
+ ret = (a_len > b_len) - (a_len < b_len);
if (ret != 0) return ret;
- return memcmp(a->name, b->name, a->length);
+ return memcmp(a->name, b->name, a_len);
}
*/
xlat_t *xlat_find(char const *name)
{
- xlat_t my_xlat;
+ xlat_t find;
+ xlat_t *found;
if (!xlat_root) return NULL;
- strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
- my_xlat.length = strlen(my_xlat.name);
+ find.name = name;
+ found = rbtree_finddata(xlat_root, &find);
- return rbtree_finddata(xlat_root, &my_xlat);
+ return found;
}
/** Register an xlat function.
*
- * @param[in] mod_inst Instance of module that's registering the xlat function.
- * @param[in] name xlat name.
- * @param[in] func xlat function to be called.
- * @param[in] escape function to sanitize any sub expansions passed to the xlat function.
- * @param[in] instantiate function to pre-parse any xlat specific data.
- * @param[in] inst_size sizeof() this xlat's instance data.
- * @param[in] buf_len Size of the output buffer to allocate when calling the function.
- * May be 0 if the function allocates its own buffer.
- * @param[in] async_safe whether or not the function is async-safe.
+ * @param[in] mod_inst Instance of module that's registering the xlat function.
+ * @param[in] name xlat name.
+ * @param[in] func xlat function to be called.
+ * @param[in] escape function to sanitize any sub expansions passed to the xlat function.
+ * @param[in] instantiate function to pre-parse any xlat specific data.
+ * @param[in] inst_size sizeof() this xlat's instance data.
+ * @param[in] buf_len Size of the output buffer to allocate when calling the function.
+ * May be 0 if the function allocates its own buffer.
+ * @param[in] async_safe whether or not the function is async-safe.
* @return
* - 0 on success.
* - -1 on failure.
size_t buf_len, bool async_safe)
{
xlat_t *c;
- xlat_t my_xlat;
+ xlat_t find;
+ bool new = false;
if (!xlat_root) xlat_init();
/*
* If it already exists, replace the instance.
*/
- strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
- my_xlat.length = strlen(my_xlat.name);
- c = rbtree_finddata(xlat_root, &my_xlat);
+ find.name = name;
+ c = rbtree_finddata(xlat_root, &find);
if (c) {
if (c->internal) {
ERROR("%s: Cannot re-define internal expansion %s", __FUNCTION__, name);
return -1;
}
- c->func = func;
- c->buf_len = buf_len;
- c->escape = escape;
- c->mod_inst = mod_inst;
- c->instantiate = instantiate;
- c->inst_size = inst_size;
- return 0;
- }
-
/*
* Doesn't exist. Create it.
*/
- c = talloc_zero(xlat_root, xlat_t);
+ } else {
+ c = talloc_zero(xlat_root, xlat_t);
+ c->name = talloc_typed_strdup(c, name);
+ new = true;
+ }
+
c->func = func;
+ c->type = XLAT_FUNC_BOXED;
c->buf_len = buf_len;
c->escape = escape;
- strlcpy(c->name, name, sizeof(c->name));
- c->length = strlen(c->name);
c->mod_inst = mod_inst;
c->instantiate = instantiate;
c->inst_size = inst_size;
DEBUG3("%s: %s", c->name, __FUNCTION__);
- if (!rbtree_insert(xlat_root, c)) {
+ if (new && !rbtree_insert(xlat_root, c)) {
+ ERROR("Failed inserting xlat registration for %s",
+ c->name);
+ talloc_free(c);
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Remove an xlat function from the function tree
+ *
+ * @param[in] xlat to free.
+ * @return 0
+ */
+static int _xlat_free(xlat_t *xlat)
+{
+ xlat_t *c;
+
+ if (!xlat_root) return 0;
+
+ c = rbtree_finddata(xlat_root, xlat);
+ if (!c) return 0;
+
+ rbtree_deletebydata(xlat_root, c);
+
+ if (rbtree_num_elements(xlat_root) == 0) TALLOC_FREE(xlat_root);
+
+ return 0;
+}
+
+/** Register an async xlat
+ *
+ * All functions registered must be async_safe.
+ *
+ * @param[in] ctx Used to automate deregistration of the xlat fnction.
+ * @param[in] name of the xlat.
+ * @param[in] func to register.
+ * @param[in] instantiate Instantiation function. Called whenever a xlat is
+ * compiled.
+ * @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] 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] uctx To pass to instantiate callbacks and the xlat function
+ * when it's called. Usually the module instance that
+ * registered the xlat.
+ * @return
+ * - 0 on success.
+ * - -1 on failure.
+ */
+int xlat_async_register(TALLOC_CTX *ctx,
+ char const *name, xlat_func_t func,
+ xlat_instantiate_t instantiate, size_t inst_size,
+ xlat_thread_instantiate_t thread_instantiate, size_t thread_inst_size,
+ void *uctx)
+{
+ xlat_t *c;
+ xlat_t find;
+ bool new = false;
+
+ if (!xlat_root) xlat_init();
+
+ if (!name || !*name) {
+ ERROR("%s: Invalid xlat name", __FUNCTION__);
+ return -1;
+ }
+
+ /*
+ * If it already exists, replace the instance.
+ */
+ find.name = name;
+ c = rbtree_finddata(xlat_root, &find);
+ if (c) {
+ if (c->internal) {
+ ERROR("%s: Cannot re-define internal expansion %s", __FUNCTION__, name);
+ return -1;
+ }
+
+ if (!c->async_safe) {
+ ERROR("%s: Cannot change async capability of %s", __FUNCTION__, name);
+ return -1;
+ }
+
+ /*
+ * Doesn't exist. Create it.
+ */
+ } else {
+ c = talloc_zero(ctx, xlat_t);
+ c->name = talloc_typed_strdup(c, name);
+ new = true;
+ }
+
+ c->func = func;
+ c->type = XLAT_FUNC_BOXED;
+ c->instantiate = instantiate;
+ c->thread_instantiate = thread_instantiate;
+ c->inst_size = inst_size;
+ c->thread_inst_size = thread_inst_size;
+ c->async_safe = true;
+ c->uctx = uctx;
+
+ talloc_set_destructor(c, _xlat_free);
+
+ DEBUG3("%s: %s", c->name, __FUNCTION__);
+
+ if (new && !rbtree_insert(xlat_root, c)) {
ERROR("Failed inserting xlat registration for %s",
c->name);
talloc_free(c);
* We can only have one function to call per name, so the passing of "func"
* here is extraneous.
*
- * @param[in] mod_inst data.
* @param[in] name xlat to unregister.
- * @param[in] func unused.
*/
-void xlat_unregister(void *mod_inst, char const *name, UNUSED xlat_func_t func)
+void xlat_unregister(char const *name)
{
xlat_t *c;
- xlat_t my_xlat;
+ xlat_t find;
if (!name || !xlat_root) return;
- strlcpy(my_xlat.name, name, sizeof(my_xlat.name));
- my_xlat.length = strlen(my_xlat.name);
-
- c = rbtree_finddata(xlat_root, &my_xlat);
+ find.name = name;
+ c = rbtree_finddata(xlat_root, &find);
if (!c) return;
- if (c->mod_inst != mod_inst) return;
-
rbtree_deletebydata(xlat_root, c);
if (rbtree_num_elements(xlat_root) == 0) TALLOC_FREE(xlat_root);
}
-static int xlat_unregister_callback(void *mod_inst, void *data)
+static int _xlat_unregister_callback(void *mod_inst, void *data)
{
xlat_t *c = (xlat_t *) data;
{
if (!xlat_root) return; /* All xlats have already been freed */
- rbtree_walk(xlat_root, RBTREE_DELETE_ORDER, xlat_unregister_callback, instance);
+ rbtree_walk(xlat_root, RBTREE_DELETE_ORDER, _xlat_unregister_callback, instance);
if (rbtree_num_elements(xlat_root) == 0) TALLOC_FREE(xlat_root);
}