#include <freeradius-devel/server/base.h>
#include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/value.h>
#include "../../rlm_cache.h"
#include <freeradius-devel/redis/base.h>
*/
static cache_status_t cache_entry_find(rlm_cache_entry_t **out,
UNUSED rlm_cache_config_t const *config, void *instance,
- request_t *request, UNUSED void *handle, uint8_t const *key, size_t key_len)
+ request_t *request, UNUSED void *handle, fr_value_box_t const *key)
{
rlm_cache_redis_t *driver = instance;
size_t i;
rlm_cache_entry_t *c;
map_list_init(&head);
- for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, key, key_len, false);
+ for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, (uint8_t const *)key->vb_strvalue, key->vb_length, false);
s_ret == REDIS_RCODE_TRY_AGAIN; /* Continue */
s_ret = fr_redis_cluster_state_next(&state, &conn, driver->cluster, request, status, &reply)) {
/*
* Grab all the data for this hash, should return an array
* of alternating keys/values which we then convert into maps.
*/
- RDEBUG3("LRANGE %pV 0 -1", fr_box_strvalue_len((char const *)key, key_len));
- reply = redisCommand(conn->handle, "LRANGE %b 0 -1", key, key_len);
+ RDEBUG3("LRANGE %pV 0 -1", key);
+ reply = redisCommand(conn->handle, "LRANGE %b 0 -1", key->vb_strvalue, key->vb_length);
status = fr_redis_command_status(conn, reply);
}
if (s_ret != REDIS_RCODE_SUCCESS) {
- RERROR("Failed retrieving entry for key \"%pV\"", fr_box_strvalue_len((char const *)key, key_len));
+ RERROR("Failed retrieving entry for key \"%pV\"", key);
error:
fr_redis_reply_free(&reply);
talloc_free(map);
}
- c->key = talloc_memdup(c, key, key_len);
- c->key_len = key_len;
+ if (unlikely(fr_value_box_copy(c, &c->key, key) < 0)) goto error;
+
map_list_move(&c->maps, &head);
*out = c;
*argv_p++ = command;
*argv_len_p++ = sizeof(command) - 1;
- *argv_p++ = (char const *)c->key;
- *argv_len_p++ = c->key_len;
+ *argv_p++ = (char const *)c->key.vb_strvalue;
+ *argv_len_p++ = c->key.vb_length;
/*
* Add the maps to the command string in reverse order
RDEBUG3("Pipelining commands");
- for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, c->key, c->key_len, false);
+ for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, (uint8_t const *)c->key.vb_strvalue, c->key.vb_length, false);
s_ret == REDIS_RCODE_TRY_AGAIN; /* Continue */
s_ret = fr_redis_cluster_state_next(&state, &conn, driver->cluster, request, status, &reply)) {
/*
pipelined++;
}
- RDEBUG3("DEL \"%pV\"", fr_box_strvalue_len((char const *)c->key, c->key_len));
+ RDEBUG3("DEL \"%pV\"", &c->key);
- if (redisAppendCommand(conn->handle, "DEL %b", c->key, c->key_len) != REDIS_OK) goto append_error;
+ if (redisAppendCommand(conn->handle, "DEL %b", (uint8_t const *)c->key.vb_strvalue, c->key.vb_length) != REDIS_OK) goto append_error;
pipelined++;
if (RDEBUG_ENABLED3) {
*/
if (fr_unix_time_ispos(c->expires)) {
RDEBUG3("EXPIREAT \"%pV\" %" PRIu64,
- fr_box_strvalue_len((char const *)c->key, c->key_len),
+ &c->key,
fr_unix_time_to_sec(c->expires));
- if (redisAppendCommand(conn->handle, "EXPIREAT %b %" PRIu64, c->key,
- c->key_len,
+ if (redisAppendCommand(conn->handle, "EXPIREAT %b %" PRIu64, (uint8_t const *)c->key.vb_strvalue, (size_t)c->key.vb_length,
fr_unix_time_to_sec(c->expires)) != REDIS_OK) goto append_error;
pipelined++;
RDEBUG3("EXEC");
* @copydetails cache_entry_expire_t
*/
static cache_status_t cache_entry_expire(UNUSED rlm_cache_config_t const *config, void *instance,
- request_t *request, UNUSED void *handle, uint8_t const *key, size_t key_len)
+ request_t *request, UNUSED void *handle, fr_value_box_t const *key)
{
rlm_cache_redis_t *driver = instance;
fr_redis_cluster_state_t state;
int s_ret;
cache_status_t cache_status;
- for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, key, key_len, false);
+ for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, (uint8_t const *)key->vb_strvalue, key->vb_length, false);
s_ret == REDIS_RCODE_TRY_AGAIN; /* Continue */
s_ret = fr_redis_cluster_state_next(&state, &conn, driver->cluster, request, status, &reply)) {
- reply = redisCommand(conn->handle, "DEL %b", key, key_len);
+ reply = redisCommand(conn->handle, "DEL %b", (uint8_t const *)key->vb_strvalue, key->vb_length);
status = fr_redis_command_status(conn, reply);
}
#include <freeradius-devel/server/module_rlm.h>
#include <freeradius-devel/server/modpriv.h>
#include <freeradius-devel/server/dl_module.h>
+#include <freeradius-devel/server/rcode.h>
#include <freeradius-devel/util/debug.h>
#include <freeradius-devel/unlang/xlat_func.h>
static const CONF_PARSER module_config[] = {
{ FR_CONF_OFFSET("driver", FR_TYPE_VOID, rlm_cache_t, driver_submodule), .dflt = "rbtree",
.func = module_rlm_submodule_parse },
- { FR_CONF_OFFSET("key", FR_TYPE_TMPL | FR_TYPE_REQUIRED, rlm_cache_config_t, key) },
{ FR_CONF_OFFSET("ttl", FR_TYPE_TIME_DELTA, rlm_cache_config_t, ttl), .dflt = "500s" },
{ FR_CONF_OFFSET("max_entries", FR_TYPE_UINT32, rlm_cache_config_t, max_entries), .dflt = "0" },
CONF_PARSER_TERMINATOR
};
+typedef struct {
+ fr_value_box_t *key;
+} cache_call_env_t;
+
+static const call_method_env_t cache_common_env = {
+ .inst_size = sizeof(cache_call_env_t),
+ .inst_type = "cache_call_env_t",
+ .env = (call_env_t[]) {
+ { FR_CALL_ENV_OFFSET("key", FR_TYPE_STRING, cache_call_env_t, key,
+ NULL, T_INVALID, true, false, true) },
+ CALL_ENV_TERMINATOR
+ }
+};
+
static fr_dict_t const *dict_freeradius;
extern fr_dict_autoload_t rlm_cache_dict[];
*/
static unlang_action_t cache_find(rlm_rcode_t *p_result, rlm_cache_entry_t **out,
rlm_cache_t const *inst, request_t *request,
- rlm_cache_handle_t **handle, uint8_t const *key, size_t key_len)
+ rlm_cache_handle_t **handle, fr_value_box_t const *key)
{
cache_status_t ret;
*out = NULL;
for (;;) {
- ret = inst->driver->find(&c, &inst->config, inst->driver_submodule->dl_inst->data, request, *handle, key, key_len);
+ ret = inst->driver->find(&c, &inst->config, inst->driver_submodule->dl_inst->data, request, *handle, key);
switch (ret) {
case CACHE_RECONNECT:
RDEBUG2("Reconnecting...");
break;
case CACHE_MISS:
- RDEBUG2("No cache entry found for \"%pV\"", fr_box_strvalue_len((char const *)key, key_len));
+ RDEBUG2("No cache entry found for \"%pV\"", key);
RETURN_MODULE_NOTFOUND;
default:
*/
if (fr_unix_time_lt(c->expires, fr_time_to_unix_time(request->packet->timestamp))) {
RDEBUG2("Found entry for \"%pV\", but it expired %pV ago at %pV (packet received %pV). Removing it",
- fr_box_strvalue_len((char const *)key, key_len),
+ key,
fr_box_time_delta(fr_unix_time_sub(fr_time_to_unix_time(request->packet->timestamp), c->expires)),
fr_box_date(c->expires),
fr_box_time(request->packet->timestamp));
expired:
- inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request, handle, c->key, c->key_len);
+ inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request, handle, key);
cache_free(inst, &c);
RETURN_MODULE_NOTFOUND; /* Couldn't find a non-expired entry */
}
if (fr_unix_time_lt(c->created, fr_unix_time_from_sec(inst->config.epoch))) {
RDEBUG2("Found entry for \"%pV\", but it was created before the current epoch. Removing it",
- fr_box_strvalue_len((char const *)key, key_len));
+ key);
goto expired;
}
- RDEBUG2("Found entry for \"%pV\"", fr_box_strvalue_len((char const *)key, key_len));
+ RDEBUG2("Found entry for \"%pV\"", key);
c->hits++;
*out = c;
*/
static unlang_action_t cache_expire(rlm_rcode_t *p_result,
rlm_cache_t const *inst, request_t *request,
- rlm_cache_handle_t **handle, uint8_t const *key, size_t key_len)
+ rlm_cache_handle_t **handle, fr_value_box_t const *key)
{
RDEBUG2("Expiring cache entry");
- for (;;) switch (inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request,
- *handle, key, key_len)) {
+ for (;;) switch (inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request, *handle, key)) {
case CACHE_RECONNECT:
if (cache_reconnect(handle, inst, request) == 0) continue;
FALL_THROUGH;
*/
static unlang_action_t cache_insert(rlm_rcode_t *p_result,
rlm_cache_t const *inst, request_t *request, rlm_cache_handle_t **handle,
- uint8_t const *key, size_t key_len, fr_time_delta_t ttl)
+ fr_value_box_t const *key, fr_time_delta_t ttl)
{
map_t const *map = NULL;
map_t *c_map;
RETURN_MODULE_FAIL;
}
map_list_init(&c->maps);
- c->key = talloc_memdup(c, key, key_len);
- c->key_len = key_len;
+ if (unlikely(fr_value_box_copy(c, &c->key, key) < 0)) {
+ RERROR("Failed copying key");
+ talloc_free(c);
+ RETURN_MODULE_FAIL;
+ }
/*
* All in NSEC resolution
{
rlm_cache_entry_t *c = NULL;
rlm_cache_t const *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_cache_t);
+ cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t);
rlm_cache_handle_t *handle;
bool merge = true, insert = true, expire = false, set_ttl = false;
int exists = -1;
- uint8_t buffer[1024];
- uint8_t const *key;
- ssize_t key_len;
rlm_rcode_t rcode = RLM_MODULE_NOOP;
fr_time_delta_t ttl = inst->config.ttl;
- key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer),
- request, inst->config.key, NULL, NULL);
- if (key_len < 0) {
- RETURN_MODULE_FAIL;
- }
-
- if (key_len == 0) {
+ if (env->key->vb_length == 0) {
REDEBUG("Zero length key string is invalid");
RETURN_MODULE_INVALID;
}
RETURN_MODULE_FAIL;
}
- cache_find(&rcode, &c, inst, request, &handle, key, key_len);
+ cache_find(&rcode, &c, inst, request, &handle, env->key);
if (rcode == RLM_MODULE_FAIL) goto finish;
fr_assert(!inst->driver->acquire || handle);
* recording whether the entry existed.
*/
if (merge) {
- cache_find(&rcode, &c, inst, request, &handle, key, key_len);
+ cache_find(&rcode, &c, inst, request, &handle, env->key);
switch (rcode) {
case RLM_MODULE_FAIL:
goto finish;
rlm_rcode_t tmp;
fr_assert(!set_ttl);
- cache_expire(&tmp, inst, request, &handle, key, key_len);
+ cache_expire(&tmp, inst, request, &handle, env->key);
switch (tmp) {
case RLM_MODULE_FAIL:
rcode = RLM_MODULE_FAIL;
if ((exists < 0) && (insert || set_ttl)) {
rlm_rcode_t tmp;
- cache_find(&tmp, &c, inst, request, &handle, key, key_len);
+ cache_find(&tmp, &c, inst, request, &handle, env->key);
switch (tmp) {
case RLM_MODULE_FAIL:
rcode = RLM_MODULE_FAIL;
if (insert && (exists == 0)) {
rlm_rcode_t tmp;
- cache_insert(&tmp, inst, request, &handle, key, key_len, ttl);
+ cache_insert(&tmp, inst, request, &handle, env->key, ttl);
switch (tmp) {
case RLM_MODULE_FAIL:
rcode = RLM_MODULE_FAIL;
{
rlm_cache_entry_t *c = NULL;
rlm_cache_t *inst = talloc_get_type_abort(xctx->mctx->inst->data, rlm_cache_t);
+ cache_call_env_t *env = talloc_get_type_abort(xctx->env_data, cache_call_env_t);
rlm_cache_handle_t *handle = NULL;
ssize_t slen;
fr_value_box_t *attr = fr_value_box_list_head(in);
- uint8_t buffer[1024];
- uint8_t const *key;
- ssize_t key_len;
fr_value_box_t *vb;
tmpl_t *target = NULL;
map_t *map = NULL;
rlm_rcode_t rcode = RLM_MODULE_NOOP;
- key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer),
- request, inst->config.key, NULL, NULL);
- if (key_len < 0) return XLAT_ACTION_FAIL;
-
slen = tmpl_afrom_attr_substr(ctx, NULL, &target,
&FR_SBUFF_IN(attr->vb_strvalue, attr->vb_length),
NULL,
return XLAT_ACTION_FAIL;
}
- cache_find(&rcode, &c, inst, request, &handle, key, key_len);
+ cache_find(&rcode, &c, inst, request, &handle, env->key);
switch (rcode) {
case RLM_MODULE_OK: /* found */
break;
}
}
-/** Free any memory allocated under the instance
- *
- */
-static int mod_detach(module_detach_ctx_t const *mctx)
-{
- rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t);
-
- /*
- * We need to explicitly free all children, so if the driver
- * parented any memory off the instance, their destructors
- * run before we unload the bytecode for them.
- *
- * If we don't do this, we get a SEGV deep inside the talloc code
- * when it tries to call a destructor that no longer exists.
- */
- talloc_free_children(inst);
-
- return 0;
-}
-
-/** Register module xlats
- *
- */
-static int mod_bootstrap(module_inst_ctx_t const *mctx)
-{
- rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t );
- xlat_t *xlat;
-
- inst->driver = (rlm_cache_driver_t const *)inst->driver_submodule->dl_inst->module->common;
-
- /*
- * Non optional fields and callbacks
- */
- fr_assert(inst->driver->common.name);
- fr_assert(inst->driver->find);
- fr_assert(inst->driver->insert);
- fr_assert(inst->driver->expire);
-
- /*
- * Register the cache xlat function
- */
- xlat = xlat_func_register_module(inst, mctx, mctx->inst->name, cache_xlat, FR_TYPE_VOID);
- xlat_func_args_set(xlat, cache_xlat_args);
-
- return 0;
-}
-
-/** Create a new rlm_cache_instance
- *
- */
-static int mod_instantiate(module_inst_ctx_t const *mctx)
-{
- rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t);
- CONF_SECTION *conf = mctx->inst->conf;
- CONF_SECTION *update;
-
- fr_assert(inst->config.key);
-
- if (!fr_time_delta_ispos(inst->config.ttl)) {
- cf_log_err(conf, "Must set 'ttl' to non-zero");
- return -1;
- }
-
- if (inst->config.epoch != 0) {
- cf_log_err(conf, "Must not set 'epoch' in the configuration files");
- return -1;
- }
-
- update = cf_section_find(conf, "update", CF_IDENT_ANY);
- if (!update) {
- cf_log_err(conf, "Must have an 'update' section in order to cache anything");
- return -1;
- }
-
- /*
- * Make sure the users don't screw up too badly.
- */
- {
- tmpl_rules_t parse_rules = {
- .attr = {
- .list_def = request_attr_request,
- .allow_wildcard = true,
- .allow_foreign = true /* Because we don't know where we'll be called */
- }
- };
-
- map_list_init(&inst->maps);
- if (map_afrom_cs(inst, &inst->maps, update,
- &parse_rules, &parse_rules, cache_verify, inst, MAX_ATTRMAP) < 0) {
- return -1;
- }
- }
-
- if (map_list_empty(&inst->maps)) {
- cf_log_err(conf, "Cache config must contain an update section, and "
- "that section must not be empty");
- return -1;
- }
-
- return 0;
-}
-
/** Get the status by ${key} (without load)
*
* @return
static unlang_action_t CC_HINT(nonnull) mod_method_status(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
{
rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t);
+ cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t);
rlm_rcode_t rcode = RLM_MODULE_NOOP;
- uint8_t buffer[1024];
- uint8_t const *key;
- ssize_t key_len;
rlm_cache_entry_t *entry = NULL;
rlm_cache_handle_t *handle = NULL;
DEBUG3("Calling %s.status", mctx->inst->name);
- key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer),
- request, inst->config.key, NULL, NULL);
- if (key_len < 0) {
- RETURN_MODULE_FAIL;
- }
-
- if (key_len == 0) {
+ if (env->key->vb_length == 0) {
REDEBUG("Zero length key string is invalid");
RETURN_MODULE_FAIL;
}
fr_assert(!inst->driver->acquire || handle);
- cache_find(&rcode, &entry, inst, request, &handle, key, key_len);
+ cache_find(&rcode, &entry, inst, request, &handle, env->key);
if (rcode == RLM_MODULE_FAIL) goto finish;
rcode = (entry) ? RLM_MODULE_OK : RLM_MODULE_NOTFOUND;
static unlang_action_t CC_HINT(nonnull) mod_method_load(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
{
rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t);
+ cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t);
rlm_rcode_t rcode = RLM_MODULE_NOOP;
- uint8_t buffer[1024];
- uint8_t const *key;
- ssize_t key_len;
rlm_cache_entry_t *entry = NULL;
rlm_cache_handle_t *handle = NULL;
DEBUG3("Calling %s.load", mctx->inst->name);
- key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer),
- request, inst->config.key, NULL, NULL);
- if (key_len < 0) {
- RETURN_MODULE_FAIL;
- }
-
- if (key_len == 0) {
+ if (env->key->vb_length == 0) {
REDEBUG("Zero length key string is invalid");
RETURN_MODULE_FAIL;
}
RETURN_MODULE_FAIL;
}
- cache_find(&rcode, &entry, inst, request, &handle, key, key_len);
+ cache_find(&rcode, &entry, inst, request, &handle, env->key);
if (rcode == RLM_MODULE_FAIL) goto finish;
if (!entry) {
static unlang_action_t CC_HINT(nonnull) mod_method_store(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
{
rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t);
+ cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t);
rlm_rcode_t rcode = RLM_MODULE_NOOP;
- uint8_t buffer[1024];
- uint8_t const *key;
- ssize_t key_len;
fr_time_delta_t ttl;
bool expire = false;
rlm_cache_entry_t *entry = NULL;
DEBUG3("Calling %s.store", mctx->inst->name);
- key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer),
- request, inst->config.key, NULL, NULL);
- if (key_len < 0) {
- RETURN_MODULE_FAIL;
- }
-
- if (key_len == 0) {
+ if (env->key->vb_length == 0) {
REDEBUG("Zero length key string is invalid");
RETURN_MODULE_FAIL;
}
/*
* We can only alter the TTL on an entry if it exists.
*/
- cache_find(&rcode, &entry, inst, request, &handle, key, key_len);
+ cache_find(&rcode, &entry, inst, request, &handle, env->key);
if (rcode == RLM_MODULE_FAIL) goto finish;
if (rcode == RLM_MODULE_OK) {
if (expire) {
DEBUG4("Set the cache expire");
- cache_expire(&rcode, inst, request, &handle, key, key_len);
+ cache_expire(&rcode, inst, request, &handle, env->key);
if (rcode == RLM_MODULE_FAIL) goto finish;
}
* setting the TTL, which precludes performing an
* insert.
*/
- cache_insert(&rcode, inst, request, &handle, key, key_len, ttl);
+ cache_insert(&rcode, inst, request, &handle, env->key, ttl);
if (rcode == RLM_MODULE_OK) rcode = RLM_MODULE_UPDATED;
finish:
static unlang_action_t CC_HINT(nonnull) mod_method_clear(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
{
rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t);
+ cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t);
rlm_rcode_t rcode = RLM_MODULE_NOOP;
- uint8_t buffer[1024];
- uint8_t const *key;
- ssize_t key_len;
rlm_cache_entry_t *entry = NULL;
rlm_cache_handle_t *handle = NULL;
DEBUG3("Calling %s.clear", mctx->inst->name);
- key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer),
- request, inst->config.key, NULL, NULL);
- if (key_len < 0) {
- RETURN_MODULE_FAIL;
- }
-
- if (key_len == 0) {
+ if (env->key->vb_length == 0) {
REDEBUG("Zero length key string is invalid");
RETURN_MODULE_FAIL;
}
RETURN_MODULE_FAIL;
}
- cache_find(&rcode, &entry, inst, request, &handle, key, key_len);
+ cache_find(&rcode, &entry, inst, request, &handle, env->key);
if (rcode == RLM_MODULE_FAIL) goto finish;
if (!entry) {
goto finish;
}
- cache_expire(&rcode, inst, request, &handle, key, key_len);
+ cache_expire(&rcode, inst, request, &handle, env->key);
finish:
cache_unref(request, inst, entry, handle);
static unlang_action_t CC_HINT(nonnull) mod_method_ttl(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
{
rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t);
+ cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t);
rlm_rcode_t rcode = RLM_MODULE_NOOP;
- uint8_t buffer[1024];
- uint8_t const *key;
- ssize_t key_len;
fr_time_delta_t ttl;
rlm_cache_entry_t *entry = NULL;
rlm_cache_handle_t *handle = NULL;
DEBUG3("Calling %s.ttl", mctx->inst->name);
- key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer),
- request, inst->config.key, NULL, NULL);
- if (key_len < 0) {
- RETURN_MODULE_FAIL;
- }
-
- if (key_len == 0) {
+ if (env->key->vb_length == 0) {
REDEBUG("Zero length key string is invalid");
RETURN_MODULE_FAIL;
}
/*
* We can only alter the TTL on an entry if it exists.
*/
- cache_find(&rcode, &entry, inst, request, &handle, key, key_len);
+ cache_find(&rcode, &entry, inst, request, &handle, env->key);
if (rcode == RLM_MODULE_FAIL) goto finish;
if (rcode == RLM_MODULE_OK) {
RETURN_MODULE_RCODE(rcode);
}
+/** Free any memory allocated under the instance
+ *
+ */
+static int mod_detach(module_detach_ctx_t const *mctx)
+{
+ rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t);
+
+ /*
+ * We need to explicitly free all children, so if the driver
+ * parented any memory off the instance, their destructors
+ * run before we unload the bytecode for them.
+ *
+ * If we don't do this, we get a SEGV deep inside the talloc code
+ * when it tries to call a destructor that no longer exists.
+ */
+ talloc_free_children(inst);
+
+ return 0;
+}
+
+/** Create a new rlm_cache_instance
+ *
+ */
+static int mod_instantiate(module_inst_ctx_t const *mctx)
+{
+ rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t);
+ CONF_SECTION *conf = mctx->inst->conf;
+ CONF_SECTION *update;
+
+ if (!fr_time_delta_ispos(inst->config.ttl)) {
+ cf_log_err(conf, "Must set 'ttl' to non-zero");
+ return -1;
+ }
+
+ if (inst->config.epoch != 0) {
+ cf_log_err(conf, "Must not set 'epoch' in the configuration files");
+ return -1;
+ }
+
+ update = cf_section_find(conf, "update", CF_IDENT_ANY);
+ if (!update) {
+ cf_log_err(conf, "Must have an 'update' section in order to cache anything");
+ return -1;
+ }
+
+ /*
+ * Make sure the users don't screw up too badly.
+ */
+ {
+ tmpl_rules_t parse_rules = {
+ .attr = {
+ .list_def = request_attr_request,
+ .allow_wildcard = true,
+ .allow_foreign = true /* Because we don't know where we'll be called */
+ }
+ };
+
+ map_list_init(&inst->maps);
+ if (map_afrom_cs(inst, &inst->maps, update,
+ &parse_rules, &parse_rules, cache_verify, inst, MAX_ATTRMAP) < 0) {
+ return -1;
+ }
+ }
+
+ if (map_list_empty(&inst->maps)) {
+ cf_log_err(conf, "Cache config must contain an update section, and "
+ "that section must not be empty");
+ return -1;
+ }
+
+ return 0;
+}
+
+/** Register module xlats
+ *
+ */
+static int mod_bootstrap(module_inst_ctx_t const *mctx)
+{
+ rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t );
+ xlat_t *xlat;
+
+ inst->driver = (rlm_cache_driver_t const *)inst->driver_submodule->dl_inst->module->common;
+
+ /*
+ * Non optional fields and callbacks
+ */
+ fr_assert(inst->driver->common.name);
+ fr_assert(inst->driver->find);
+ fr_assert(inst->driver->insert);
+ fr_assert(inst->driver->expire);
+
+ /*
+ * Register the cache xlat function
+ */
+ xlat = xlat_func_register_module(inst, mctx, mctx->inst->name, cache_xlat, FR_TYPE_VOID);
+ xlat_func_args_set(xlat, cache_xlat_args);
+ xlat_func_call_env_set(xlat, &cache_common_env);
+
+ return 0;
+}
+
/*
* The module name should be the only globally exported symbol.
* That is, everything else should be 'static'.
.detach = mod_detach
},
.method_names = (module_method_name_t[]){
- { .name1 = "status", .name2 = CF_IDENT_ANY, .method = mod_method_status },
- { .name1 = "load", .name2 = CF_IDENT_ANY, .method = mod_method_load },
- { .name1 = "store", .name2 = CF_IDENT_ANY, .method = mod_method_store },
- { .name1 = "clear", .name2 = CF_IDENT_ANY, .method = mod_method_clear },
- { .name1 = "ttl", .name2 = CF_IDENT_ANY, .method = mod_method_ttl },
- { .name1 = CF_IDENT_ANY, .name2 = CF_IDENT_ANY, .method = mod_cache_it },
+ { .name1 = "status", .name2 = CF_IDENT_ANY, .method = mod_method_status, .method_env = &cache_common_env },
+ { .name1 = "load", .name2 = CF_IDENT_ANY, .method = mod_method_load, .method_env = &cache_common_env },
+ { .name1 = "store", .name2 = CF_IDENT_ANY, .method = mod_method_store, .method_env = &cache_common_env },
+ { .name1 = "clear", .name2 = CF_IDENT_ANY, .method = mod_method_clear, .method_env = &cache_common_env },
+ { .name1 = "ttl", .name2 = CF_IDENT_ANY, .method = mod_method_ttl, .method_env = &cache_common_env },
+ { .name1 = CF_IDENT_ANY, .name2 = CF_IDENT_ANY, .method = mod_cache_it, .method_env = &cache_common_env },
MODULE_NAME_TERMINATOR
}
};