29RCSID(
"$Id: 50bd6cacb724a2dc7d475ea4d275fb903c11f23f $")
31#include <freeradius-devel/server/base.h>
32#include <freeradius-devel/server/module_rlm.h>
33#include <freeradius-devel/server/modpriv.h>
34#include <freeradius-devel/util/debug.h>
36#include <freeradius-devel/redis/base.h>
37#include <freeradius-devel/redis/cluster_async.h>
115 switch (reply->type) {
116 case REDIS_REPLY_INTEGER:
117 rediswho_rctx->
ret = reply->integer;
120 case REDIS_REPLY_STATUS:
121 if (strcmp(reply->str,
"OK") != 0) {
122 REDEBUG(
"Redis returned %s", reply->str);
123 rediswho_rctx->
ret = -1;
131 REDEBUG(
"Bad result type, expected integer, got %s",
133 rediswho_rctx->
ret = -1;
155 redisFreeCommand(rctx->
cmd_str);
161 cmd_len = redisvFormatCommand(&rctx->
cmd_str,
fmt, ap);
165 RERROR(
"Failed formatting redis commmand");
172 (
uint8_t const *)key->vb_strvalue, key->vb_length, rctx->
cmds,
false, NULL);
181 RDEBUG2(
"Forcibly cancelling Redis command");
197 inst->coord_pair_reg,
false);
224 RPERROR(
"Redis command failed");
244 RPERROR(
"Redis command failed");
253 RDEBUG3(
"Setting expiry to %d",
inst->expiry_time);
271 RPERROR(
"Redis command failed");
277 if (rctx->
ret >
inst->trim_count) {
279 (
uint8_t const *)env->
key.vb_strvalue, env->
key.vb_length,
inst->trim_count - 1);
283 RDEBUG3(
"Trimming \"%pV\" to %d entries", &env->
key,
inst->trim_count);
310 if (env->
key.vb_length == 0) {
311 RDEBUG2(
"Zero length key value");
316 RDEBUG2(
"Zero length argument value");
357 ERROR(
"Failed to attach to coordinator");
374 inst->conf.module_name = mctx->
mi->module->
name;
377 if (
inst->conf.use_tls) {
380 if (!
inst->tls_conf) {
386 if (!
inst->conf.use_cluster_map)
return 0;
388 if (
inst->conf.database) {
389 cf_log_err(mctx->
mi->
conf,
"Cannot set Redis database number when cluster in use");
395 .worker_cb = worker_pair_callbacks,
396 .cb_id = REDIS_COORD_PAIR_CALLBACK_ID,
401 if (!
inst->coord_pair_reg)
return -1;
407 .coord_cb = coord_callbacks,
408 .worker_cb = worker_callbacks,
412 if (!
inst->coord_reg)
return -1;
421 if (!t->
cw)
return 0;
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
static int const char * fmt
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
int call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *parsed, char const *name, tmpl_rules_t const *t_rules, CONF_SECTION const *cs, call_env_ctx_t const *cec, call_env_parser_t const *rule)
Parse per call env.
#define CALL_ENV_TERMINATOR
call_env_ctx_type_t type
Type of callenv ctx.
@ CALL_ENV_CTX_TYPE_MODULE
The callenv is registered to a module method.
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
call_env_parser_t const * env
Parsing rules for call method env.
section_name_t const * asked
The actual name1/name2 that resolved to a module_method_binding_t.
@ CALL_ENV_FLAG_CONCAT
If the tmpl produced multiple boxes they should be concatenated.
@ CALL_ENV_FLAG_SUBSECTION
This is a subsection.
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
#define FR_CALL_ENV_SUBSECTION_FUNC(_name, _name2, _flags, _func)
Specify a call_env_parser_t which parses a subsection using a callback function.
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Defines a CONF_PAIR to C data type mapping.
Common header for all CONF_* types.
A section grouping multiple CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
#define cf_log_err(_cf, _fmt,...)
#define cf_log_warn(_cf, _fmt,...)
int fr_redis_ct_map_bootstrap(fr_redis_ct_t *rtcluster, fr_coord_worker_t *cw, fr_coord_pair_reg_t *coord_pair_reg)
Initiate bootstrapping of the cluster map.
fr_redis_async_cmd_t * fr_redis_async_cmd_start(TALLOC_CTX *ctx, request_t *request, fr_redis_async_rcode_t *rcode, fr_redis_ct_t *rtcluster, uint8_t const *key, size_t key_len, fr_redis_command_set_t *cmds, bool read_only, fr_redis_ct_node_t *node)
Start running a command set on an async redis cluster.
fr_redis_async_rcode_t fr_redis_ct_map_get(fr_redis_ct_t *rtcluster, fr_coord_worker_t *cw, fr_coord_pair_reg_t *coord_pair_reg, bool force)
Initiate updating of the cluster map.
void fr_redis_async_cmd_cancel(fr_redis_async_cmd_t *cmd)
Cancel a Redis async command.
fr_redis_async_rcode_t fr_redis_async_cmd_resend(fr_redis_async_cmd_t *cmd)
Re-submit a redis async command set.
fr_redis_async_rcode_t fr_redis_async_cmd_redirect(fr_redis_async_cmd_t *cmd)
Re-submit a redis async command set on a different node.
fr_redis_ct_t * fr_redis_ct_alloc(TALLOC_CTX *ctx, CONF_SECTION *tls_cs, fr_event_list_t *el, fr_redis_conf_t *conf, fr_redis_trunk_active_t active, void *active_uctx, bool active_oneshot)
Allocate per-thread, per-cluster instance.
Structure for holding the state of an async redis command set.
Thread local state for a cluster.
#define REDIS_ASYNC_COORD_CALLBACKS(_thread_type)
#define REDIS_ASYNC_START_RCODE_PROCESS(_rcode, _cluster, _cw, _coord_pair_reg, _error_msg, _error_ret)
Convenience macro to reduce boilerplate.
fr_coord_reg_t * fr_coord_register(fr_coord_reg_ctx_t *reg_ctx)
Register a coordinator.
fr_coord_worker_t * fr_coord_attach(TALLOC_CTX *ctx, fr_event_list_t *el, fr_coord_reg_t *coord_reg)
Attach a worker to a coordinator.
void fr_coord_deregister(fr_coord_reg_t *coord_reg)
De-register a coordinator.
int fr_coord_detach(fr_coord_worker_t *cw, bool exiting)
Signal a coordinator that a worker wants to detach.
A coordinator registration.
The worker end of worker <-> coordinator communication.
fr_coord_pair_reg_t * fr_coord_pair_register(fr_coord_pair_reg_ctx_t *reg_ctx)
Register a set of callbacks for pair list based coordinator messages.
struct fr_coord_pair_reg_s fr_coord_pair_reg_t
#define FR_COORD_PAIR_CB_CTX_SET(_in_cb, _out_cb, _reg)
Set up ctx on pair list callbacks.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
#define DICT_AUTOLOAD_TERMINATOR
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
void * thread
Thread specific instance data.
void * rctx
Resume ctx that a module previously set.
fr_event_list_t * el
Event list to register any IO handlers and timers against.
module_instance_t * mi
Module instance to detach.
void * thread
Thread instance data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for detach calls.
Temporary structure to hold arguments for instantiation calls.
Temporary structure to hold arguments for thread_instantiation calls.
module_t common
Common fields presented by all modules.
fr_redis_async_rcode_t fr_redis_command_set_rcode(fr_redis_command_set_t *cmds)
Extract the rcode from a command set.
fr_redis_pipeline_status_t fr_redis_command_preformatted_add(fr_redis_command_set_t *cmds, char const *cmd_str, size_t cmd_len, fr_redis_command_complete_t complete, void *rctx)
Add an preformatted command to the command set as formatted by redisCommandFormat or it's variants.
fr_redis_command_set_t * fr_redis_command_set_alloc(TALLOC_CTX *ctx, request_t *request, fr_redis_command_set_complete_t complete, fr_redis_command_set_fail_t fail, void *rctx, bool autofree)
Allocate a new command set.
int fr_redis_command_set_clear(fr_redis_command_set_t *cmds)
Represents a single command.
Represents a collection of pipelined commands.
@ FR_REDIS_PIPELINE_OK
No failure.
static const conf_parser_t config[]
#define RETURN_UNLANG_FAIL
#define RETURN_UNLANG_NOOP
#define REDIS_COMMON_CONFIG
@ REDIS_ASYNC_RCODE_MOVE
Attempt operation on an alternative node with remap.
@ REDIS_ASYNC_RCODE_ERROR
Unrecoverable error.
@ REDIS_ASYNC_RCODE_ASK
Attempt operation on an alternative node.
@ REDIS_ASYNC_RCODE_TRY_AGAIN
Try the operation again.
@ REDIS_ASYNC_RCODE_SUCCESS
Operation was successful.
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
fr_table_num_sorted_t const redis_reply_types[]
Configuration parameters for a redis connection.
static int mod_detach(module_detach_ctx_t const *mctx)
static int mod_load(void)
fr_value_box_t insert_cmd
Command to run for insert stage, defaults to LPUSH.
fr_dict_autoload_t rlm_rediswho_dict[]
fr_dict_attr_autoload_t rlm_rediswho_dict_attr[]
CONF_SECTION * tls_conf
TLS CONF_SECTION.
int trim_count
How many session updates to keep track of per user.
fr_redis_command_set_t * cmds
Command set for module call.
static int mod_coord_attach(module_thread_inst_ctx_t const *mctx)
int expiry_time
Expiry time in seconds if no updates are received for a user.
char * cmd_str
Formatted command currently being run.
fr_value_box_t key
Key value for redis commands.
static void mod_accounting_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
fr_coord_reg_t * coord_reg
Coordinator registration.
static const call_env_method_t method_env
fr_redis_conf_t conf
Connection parameters for the Redis server.
fr_value_box_t trim_cmd
Command to run for trim stage, defaults to LTRIM.
static int _rediswho_rctx_free(rediswho_rctx_t *rctx)
static fr_dict_t const * dict_radius
static unlang_action_t mod_accounting(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static call_env_parser_t const rediswho_env_parser[]
static fr_redis_async_rcode_t rediswho_command(rlm_rediswho_thread_t *thread, request_t *request, fr_value_box_t *key, rediswho_rctx_t *rctx, char const *fmt,...)
static unlang_action_t mod_accounting_resume(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static conf_parser_t redis_config[]
rlm_rediswho_t * inst
Module instance.
fr_value_box_t insert_arg
Argument to append to insert command.
static unlang_action_t mod_accounting_trim(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_dict_t const * dict_redis
module_rlm_t rlm_rediswho
fr_redis_async_cmd_t * cmd
Async command context.
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
static void rediswho_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
Process redisReply from rediswho command.
static fr_dict_attr_t const * attr_acct_status_type
fr_coord_worker_t * cw
Coord-worker for fetching cluster map.
int ret
Value returned in Redis reply.
static unlang_action_t rediswho_rcode_check(request_t *request, fr_redis_command_set_t *cmds, fr_redis_async_cmd_t *cmd, module_ctx_t const *mctx, module_method_t resume, unlang_module_signal_t cancel)
static unlang_action_t mod_accounting_expire(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static int redis_command_call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
fr_coord_pair_reg_t * coord_pair_reg
Coord pair registration.
static int mod_thread_detach(module_thread_inst_ctx_t const *mctx)
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_redis_ct_t * rtcluster
Per thread Redis cluster.
static conf_parser_t module_config[]
Resume context for rediswho module calls.
int fr_schedule_worker_id(void)
Return the worker id for the current thread.
static char const * section_name_str(char const *name)
Return a printable string for the section name.
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
char const * name2
Second section name. Usually a packet type like 'access-request', 'access-accept',...
#define MODULE_THREAD_INST(_ctype)
char const * name
Instance name e.g. user_database.
CONF_SECTION * conf
Module's instance configuration.
size_t inst_size
Size of the module's instance data.
void * data
Module's instance data.
unlang_action_t(* module_method_t)(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Module section callback.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
Optional arguments passed to vp_tmpl functions.
fr_signal_t
Signals that can be generated/processed by request signal handlers.
@ FR_SIGNAL_CANCEL
Request has been cancelled.
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
eap_aka_sim_process_conf_t * inst
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
#define talloc_get_type_abort_const
#define talloc_strdup(_ctx, _str)
void(* unlang_module_signal_t)(module_ctx_t const *mctx, request_t *request, fr_signal_t action)
A callback when the request gets a fr_signal_t.
static size_t char ** out