The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
rlm_rediswho.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: c6bd8ef906402c0dafa035a02397e1436b99b1ca $
19 * @file rlm_rediswho.c
20 * @brief Session tracking using redis.
21 *
22 * @author Gabriel Blanchard
23 *
24 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25 * @copyright 2011 TekSavvy Solutions (gabe@teksavvy.com)
26 * @copyright 2000,2006 The FreeRADIUS server project
27 */
28
29RCSID("$Id: c6bd8ef906402c0dafa035a02397e1436b99b1ca $")
30
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>
35
36#include <freeradius-devel/redis/base.h>
37#include <freeradius-devel/redis/cluster_async.h>
38
39typedef struct {
40 fr_redis_conf_t conf; //!< Connection parameters for the Redis server.
41 //!< Must be first field in this struct.
42
43
44 fr_coord_reg_t *coord_reg; //!< Coordinator registration.
45 fr_coord_pair_reg_t *coord_pair_reg; //!< Coord pair registration.
46
47 int expiry_time; //!< Expiry time in seconds if no updates are received for a user
48
49 int trim_count; //!< How many session updates to keep track of per user.
51
52typedef struct {
53 rlm_rediswho_t *inst; //!< Module instance.
54 fr_redis_ct_t *rtcluster; //!< Per thread Redis cluster.
55 fr_coord_worker_t *cw; //!< Coord-worker for fetching cluster map.
57
58/** Resume context for rediswho module calls.
59 */
60typedef struct {
61 fr_redis_command_set_t *cmds; //!< Command set for module call.
62 fr_redis_async_cmd_t *cmd; //!< Async command context.
63 char *cmd_str; //!< Formatted command currently being run.
64 int ret; //!< Value returned in Redis reply.
66
67typedef struct {
68 fr_value_box_t key; //!< Key value for redis commands
69 fr_value_box_t insert_cmd; //!< Command to run for insert stage, defaults to LPUSH
70 fr_value_box_t insert_arg; //!< Argument to append to insert command
71 fr_value_box_t trim_cmd; //!< Command to run for trim stage, defaults to LTRIM
73
78
80 { FR_CONF_OFFSET("trim_count", rlm_rediswho_t, trim_count), .dflt = "-1" },
81 { FR_CONF_OFFSET_FLAGS("expiry_time", CONF_FLAG_REQUIRED, rlm_rediswho_t, expiry_time) },
82
83 { FR_CONF_POINTER("redis", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = redis_config },
84
86};
87
88static fr_dict_t const *dict_radius;
89static fr_dict_t const *dict_redis;
90
93 { .out = &dict_radius, .proto = "radius" },
94 { .out = &dict_redis, .proto = "redis" },
96};
97
99
102 { .out = &attr_acct_status_type, .name = "Acct-Status-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
104};
105
106/** Process redisReply from rediswho command
107 *
108 * The reply is expected to either be an integer or status.
109 */
110static void rediswho_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
111{
112 rediswho_rctx_t *rediswho_rctx = talloc_get_type_abort(rctx, rediswho_rctx_t);
113
114 switch (reply->type) {
115 case REDIS_REPLY_INTEGER:
116 rediswho_rctx->ret = reply->integer;
117 return;
118
119 case REDIS_REPLY_STATUS:
120 if (strcmp(reply->str, "OK") != 0) {
121 REDEBUG("Redis returned %s", reply->str);
122 rediswho_rctx->ret = -1;
123 return;
124 }
125
126 rediswho_rctx = 0;
127 return;
128
129 default:
130 REDEBUG("Bad result type, expected integer, got %s",
131 fr_table_str_by_value(redis_reply_types, reply->type, "<UNKNOWN>"));
132 rediswho_rctx->ret = -1;
133 return;
134 }
135
136}
137
138/*
139 * Enqueue a Redis command which will return a single integer or status result.
140 */
142 rediswho_rctx_t *rctx, char const *fmt, ...)
143{
144 va_list ap;
146 int cmd_len;
147
148 if (!fmt || !*fmt) return REDIS_ASYNC_RCODE_ERROR;
149
150 /*
151 * If there's a previous formatted command, clean up
152 */
153 if (rctx->cmd_str) {
154 redisFreeCommand(rctx->cmd_str);
155 rctx->cmd_str = NULL;
157 }
158
159 va_start(ap, fmt);
160 cmd_len = redisvFormatCommand(&rctx->cmd_str, fmt, ap);
161 va_end(ap);
162
163 if (cmd_len < 0) {
164 RERROR("Failed formatting redis commmand");
166 }
169
170 rctx->cmd = fr_redis_async_cmd_start(rctx, request, &ret, thread->rtcluster,
171 (uint8_t const *)key->vb_strvalue, key->vb_length, rctx->cmds, false, NULL);
172
173 return ret;
174}
175
177{
178 rediswho_rctx_t *rctx = talloc_get_type_abort(mctx->rctx, rediswho_rctx_t);
179
180 RDEBUG2("Forcibly cancelling Redis command");
181
183}
184
186 fr_redis_async_cmd_t *cmd, module_ctx_t const *mctx,
188{
189 switch (fr_redis_command_set_rcode(cmds)) {
191 {
193 rlm_rediswho_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
194
195 if (inst->conf.use_cluster_map) fr_redis_ct_map_get(thread->rtcluster, thread->cw,
196 inst->coord_pair_reg, false);
197 }
199
202 return unlang_module_yield(request, resume, cancel, ~FR_SIGNAL_CANCEL, mctx->rctx);
203
206 return unlang_module_yield(request, resume, cancel, ~FR_SIGNAL_CANCEL, mctx->rctx);
207
208 default:
209 break;
210 }
212}
213
216{
217 rediswho_rctx_t *rctx = talloc_get_type_abort(mctx->rctx, rediswho_rctx_t);
218
221
222 if (rctx->ret < 0) {
223 RPERROR("Redis command failed");
225 }
226
228}
229
232{
233 rediswho_rctx_t *rctx = talloc_get_type_abort(mctx->rctx, rediswho_rctx_t);
235 rlm_rediswho_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
236 rediswho_call_env_t *env = talloc_get_type_abort(mctx->env_data, rediswho_call_env_t);
238
241
242 if (rctx->ret < 0) {
243 RPERROR("Redis command failed");
245 }
246
247 ret = rediswho_command(thread, request, &env->key, rctx, "EXPIRE %b %d",
248 (uint8_t const *)env->key.vb_strvalue, env->key.vb_length, inst->expiry_time);
249
250 REDIS_ASYNC_START_RCODE_PROCESS(ret, thread->rtcluster, thread->cw, thread->inst->coord_pair_reg,
251 "Failed to enqueue Redis cache find commands", UNLANG_ACTION_FAIL)
252 RDEBUG3("Setting expiry to %d", inst->expiry_time);
253
255}
256
259{
260 rediswho_rctx_t *rctx = talloc_get_type_abort(mctx->rctx, rediswho_rctx_t);
262 rlm_rediswho_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
263 rediswho_call_env_t *env = talloc_get_type_abort(mctx->env_data, rediswho_call_env_t);
265
268
269 if (rctx->ret < 0) {
270 RPERROR("Redis command failed");
272 }
273
274 RDEBUG3("Key \"%pV\" has %d entries", &env->key, rctx->ret);
275
276 if (rctx->ret > inst->trim_count) {
277 ret = rediswho_command(thread, request, &env->key, rctx, "%s %b 0 %d", env->trim_cmd.vb_strvalue,
278 (uint8_t const *)env->key.vb_strvalue, env->key.vb_length, inst->trim_count - 1);
279
280 REDIS_ASYNC_START_RCODE_PROCESS(ret, thread->rtcluster, thread->cw, thread->inst->coord_pair_reg,
281 "Failed to enqueue Redis cache find commands", UNLANG_ACTION_FAIL)
282 RDEBUG3("Trimming \"%pV\" to %d entries", &env->key, inst->trim_count);
284 }
285
286 ret = rediswho_command(thread, request, &env->key, rctx, "EXPIRE %b %d",
287 (uint8_t const *)env->key.vb_strvalue, env->key.vb_length, inst->expiry_time);
288
289 REDIS_ASYNC_START_RCODE_PROCESS(ret, thread->rtcluster, thread->cw, thread->inst->coord_pair_reg,
290 "Failed to enqueue Redis cache find commands", UNLANG_ACTION_FAIL)
291
293}
294
296{
297 if (rctx->cmd_str) redisFreeCommand(rctx->cmd_str);
298 return 0;
299}
300
302{
304 rlm_rediswho_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
305 rediswho_call_env_t *env = talloc_get_type_abort(mctx->env_data, rediswho_call_env_t);
307 rediswho_rctx_t *rctx;
308
309 if (env->key.vb_length == 0) {
310 RDEBUG2("Zero length key value");
312 }
313
314 if (env->insert_arg.vb_length == 0) {
315 RDEBUG2("Zero length argument value");
317 }
318
320 *rctx = (rediswho_rctx_t) { .ret = -1 };
321 rctx->cmds = fr_redis_command_set_alloc(rctx, request, NULL, NULL, NULL, false);
322 talloc_set_destructor(rctx, _rediswho_rctx_free);
323
324 ret = rediswho_command(thread, request, &env->key, rctx, "%s %b %b", env->insert_cmd.vb_strvalue,
325 (uint8_t const *)env->key.vb_strvalue, env->key.vb_length,
326 (uint8_t const *)env->insert_arg.vb_strvalue, env->insert_arg.vb_length);
327
328 REDIS_ASYNC_START_RCODE_PROCESS(ret, thread->rtcluster, thread->cw, thread->inst->coord_pair_reg,
329 "Failed to enqueue Redis cache find commands", UNLANG_ACTION_FAIL)
330
332 mod_accounting_cancel, ~FR_SIGNAL_CANCEL, rctx);
333}
334
336{
337 rlm_rediswho_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
338 rlm_rediswho_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_rediswho_t);
339
340 t->rtcluster = fr_redis_ct_alloc(t, mctx->el, &inst->conf, NULL, NULL, false);
341
342 if (!t->rtcluster) return -1;
343 t->inst = inst;
344
345 return 0;
346}
347
349{
350 rlm_rediswho_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
351 rlm_rediswho_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_rediswho_t);
352
353 t->cw = fr_coord_attach(t, mctx->el, inst->coord_reg);
354
355 if (!t->cw) {
356 ERROR("Failed to attach to coordinator");
357 return -1;
358 }
359
360 if ((inst->conf.trunk_conf.start == 0) || (fr_schedule_worker_id() != 0)) return 0;
361
362 return fr_redis_ct_map_bootstrap(t->rtcluster, t->cw, inst->coord_pair_reg);
363}
364
366
367static int mod_instantiate(module_inst_ctx_t const *mctx)
368{
369 rlm_rediswho_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_rediswho_t);
370 CONF_SECTION *subcs = cf_section_find(mctx->mi->conf, "redis", NULL);
371
372 inst->conf.log_prefix = mctx->mi->name;
373 inst->conf.module_name = mctx->mi->module->name;
374 inst->conf.inst_name = mctx->mi->name;
375
376#ifdef HAVE_REDIS_SSL
377 if (inst->conf.use_tls && !inst->conf.tls) {
378 cf_log_err(mctx->mi->conf, "Missing tls section");
379 return -1;
380 }
381#endif
382
383 if (!inst->conf.use_cluster_map) return 0;
384
385 if (inst->conf.database) {
386 cf_log_err(mctx->mi->conf, "Cannot set Redis database number when cluster in use");
387 return -1;
388 }
389
391 .name = mctx->mi->name,
392 .worker_cb = worker_pair_callbacks,
393 .cb_id = REDIS_COORD_PAIR_CALLBACK_ID,
394 .root = fr_dict_root(dict_redis),
395 .cs = subcs,
396 }
397 );
398 if (!inst->coord_pair_reg) return -1;
399
400 FR_COORD_PAIR_CB_CTX_SET(coord_callbacks, worker_callbacks, inst->coord_pair_reg);
401
403 .name = mctx->mi->name,
404 .coord_cb = coord_callbacks,
405 .worker_cb = worker_callbacks,
406 .mi = mctx->mi
407 });
408
409 if (!inst->coord_reg) return -1;
410
411 return 0;
412}
413
415{
416 rlm_rediswho_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
417
418 if (!t->cw) return 0;
419
420 fr_coord_detach(t->cw, true);
421 t->cw = NULL;
422 return 0;
423}
424
425static int mod_detach(module_detach_ctx_t const *mctx)
426{
427 rlm_rediswho_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_rediswho_t);
428
429 fr_coord_deregister(inst->coord_reg);
430 talloc_free(inst->coord_pair_reg);
431 return 0;
432}
433
434static int mod_load(void)
435{
437
438 return 0;
439}
440
448
449static int redis_command_call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, tmpl_rules_t const *t_rules,
450 CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
451{
452 CONF_SECTION const *subcs = NULL;
453 char *section2, *p;
454
456
457 section2 = talloc_strdup(NULL, section_name_str(cec->asked->name2));
458 p = section2;
459 while (*p != '\0') {
460 *(p) = tolower((uint8_t)*p);
461 p++;
462 }
464 talloc_free(section2);
465 if (!subcs) {
466 cf_log_warn(ci, "No \"%s\" section found", section_name_str(cec->asked->name2) );
467 return 0;
468 }
469
470 return call_env_parse(ctx, out, cec->asked->name2, t_rules, subcs, cec, rediswho_env_parser);
471}
472
480
483 .common = {
484 .magic = MODULE_MAGIC_INIT,
485 .name = "rediswho",
486 .inst_size = sizeof(rlm_rediswho_t),
488 .onload = mod_load,
489 .instantiate = mod_instantiate,
490 .coord_attach = mod_coord_attach,
491 .coord_detach = mod_coord_detach,
492 .detach = mod_detach,
494 .thread_instantiate = mod_thread_instantiate,
495 },
496 .method_group = {
497 .bindings = (module_method_binding_t[]){
498 { .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting, .method_env = &method_env },
500 }
501 }
502};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:38
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:42
va_end(args)
static int const char * fmt
Definition acutest.h:632
va_start(args, fmt)
static uint8_t request[4]
static uint8_t reply[4]
#define RCSID(id)
Definition build.h:560
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:391
#define UNUSED
Definition build.h:384
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.
Definition call_env.c:460
#define CALL_ENV_TERMINATOR
Definition call_env.h:236
call_env_ctx_type_t type
Type of callenv ctx.
Definition call_env.h:227
@ CALL_ENV_CTX_TYPE_MODULE
The callenv is registered to a module method.
Definition call_env.h:222
#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...
Definition call_env.h:240
call_env_parser_t const * env
Parsing rules for call method env.
Definition call_env.h:247
section_name_t const * asked
The actual name1/name2 that resolved to a module_method_binding_t.
Definition call_env.h:232
@ CALL_ENV_FLAG_CONCAT
If the tmpl produced multiple boxes they should be concatenated.
Definition call_env.h:76
@ CALL_ENV_FLAG_SUBSECTION
This is a subsection.
Definition call_env.h:87
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
Definition call_env.h:75
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
Definition call_env.h:92
#define FR_CALL_ENV_SUBSECTION_FUNC(_name, _name2, _flags, _func)
Specify a call_env_parser_t which parses a subsection using a callback function.
Definition call_env.h:412
#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.
Definition call_env.h:340
Per method call config.
Definition call_env.h:180
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:696
#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
Definition cf_parse.h:280
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition cf_parse.h:334
#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
Definition cf_parse.h:268
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition cf_parse.h:450
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition cf_parse.h:444
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:633
Common header for all CONF_* types.
Definition cf_priv.h:54
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1235
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:671
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:340
#define cf_parent(_cf)
Definition cf_util.h:115
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:341
#define CF_IDENT_ANY
Definition cf_util.h:80
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_ct_t * fr_redis_ct_alloc(TALLOC_CTX *ctx, 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.
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.
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.
Definition coord.c:137
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.
Definition coord.c:691
void fr_coord_deregister(fr_coord_reg_t *coord_reg)
De-register a coordinator.
Definition coord.c:172
int fr_coord_detach(fr_coord_worker_t *cw, bool exiting)
Signal a coordinator that a worker wants to detach.
Definition coord.c:652
A coordinator registration.
Definition coord.c:85
The worker end of worker <-> coordinator communication.
Definition coord.c:73
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.
Definition coord_pair.c:113
struct fr_coord_pair_reg_s fr_coord_pair_reg_t
Definition coord_pair.h:32
#define FR_COORD_PAIR_CB_CTX_SET(_in_cb, _out_cb, _reg)
Set up ctx on pair list callbacks.
Definition coord_pair.h:93
#define MEM(x)
Definition debug.h:38
#define ERROR(fmt,...)
Definition dhcpclient.c:40
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition dict_util.c:2720
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:316
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:329
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:335
Specifies an attribute which must be present for the module to function.
Definition dict.h:315
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:328
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
talloc_free(hp)
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:2053
#define RDEBUG3(fmt,...)
Definition log.h:360
#define RERROR(fmt,...)
Definition log.h:315
#define RPERROR(fmt,...)
Definition log.h:319
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
unsigned char uint8_t
void * env_data
Per call environment data.
Definition module_ctx.h:44
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
void * thread
Thread specific instance data.
Definition module_ctx.h:43
void * rctx
Resume ctx that a module previously set.
Definition module_ctx.h:45
fr_event_list_t * el
Event list to register any IO handlers and timers against.
Definition module_ctx.h:68
module_instance_t * mi
Module instance to detach.
Definition module_ctx.h:57
void * thread
Thread instance data.
Definition module_ctx.h:67
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:64
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for detach calls.
Definition module_ctx.h:56
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
Temporary structure to hold arguments for thread_instantiation calls.
Definition module_ctx.h:63
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
fr_redis_async_rcode_t fr_redis_command_set_rcode(fr_redis_command_set_t *cmds)
Extract the rcode from a command set.
Definition pipeline.c:1040
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.
Definition pipeline.c:482
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.
Definition pipeline.c:252
int fr_redis_command_set_clear(fr_redis_command_set_t *cmds)
Reinitialise a command set so that it can be used again.
Definition pipeline.c:1106
Represents a single command.
Definition pipeline.c:62
Represents a collection of pipelined commands.
Definition pipeline.c:94
@ FR_REDIS_PIPELINE_OK
No failure.
Definition pipeline.h:44
static const conf_parser_t config[]
Definition base.c:162
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG2(fmt,...)
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
#define RETURN_UNLANG_OK
Definition rcode.h:64
#define RETURN_UNLANG_NOOP
Definition rcode.h:69
#define REDIS_COMMON_CONFIG
Definition base.h:171
fr_redis_async_rcode_t
Definition base.h:90
@ REDIS_ASYNC_RCODE_MOVE
Attempt operation on an alternative node with remap.
Definition base.h:98
@ REDIS_ASYNC_RCODE_ERROR
Unrecoverable error.
Definition base.h:92
@ REDIS_ASYNC_RCODE_ASK
Attempt operation on an alternative node.
Definition base.h:97
@ REDIS_ASYNC_RCODE_TRY_AGAIN
Try the operation again.
Definition base.h:96
@ REDIS_ASYNC_RCODE_SUCCESS
Operation was successful.
Definition base.h:91
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
Definition redis.c:107
fr_table_num_sorted_t const redis_reply_types[]
Definition redis.c:31
Configuration parameters for a redis connection.
Definition base.h:124
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[]
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 int mod_coord_detach(module_thread_inst_ctx_t const *mctx)
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_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.
Definition schedule.c:111
static char const * section_name_str(char const *name)
Return a printable string for the section name.
Definition section.h:97
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:39
char const * name2
Second section name. Usually a packet type like 'access-request', 'access-accept',...
Definition section.h:45
#define MODULE_THREAD_INST(_ctype)
Definition module.h:260
char const * name
Instance name e.g. user_database.
Definition module.h:359
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:353
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:295
unlang_action_t(* module_method_t)(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Module section callback.
Definition module.h:69
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:343
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
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.
Definition module.c:431
eap_aka_sim_process_conf_t * inst
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
#define talloc_get_type_abort_const
Definition talloc.h:117
#define talloc_strdup(_ctx, _str)
Definition talloc.h:149
@ T_SINGLE_QUOTED_STRING
Definition token.h:120
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.
Definition module.h:81
static fr_sbuff_err_t char ** out
Definition value.h:1061
int nonnull(2, 5))