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: 50bd6cacb724a2dc7d475ea4d275fb903c11f23f $
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: 50bd6cacb724a2dc7d475ea4d275fb903c11f23f $")
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 CONF_SECTION *tls_conf; //!< TLS CONF_SECTION
44
45 fr_coord_reg_t *coord_reg; //!< Coordinator registration.
46 fr_coord_pair_reg_t *coord_pair_reg; //!< Coord pair registration.
47
48 int expiry_time; //!< Expiry time in seconds if no updates are received for a user
49
50 int trim_count; //!< How many session updates to keep track of per user.
52
53typedef struct {
54 rlm_rediswho_t *inst; //!< Module instance.
55 fr_redis_ct_t *rtcluster; //!< Per thread Redis cluster.
56 fr_coord_worker_t *cw; //!< Coord-worker for fetching cluster map.
58
59/** Resume context for rediswho module calls.
60 */
61typedef struct {
62 fr_redis_command_set_t *cmds; //!< Command set for module call.
63 fr_redis_async_cmd_t *cmd; //!< Async command context.
64 char *cmd_str; //!< Formatted command currently being run.
65 int ret; //!< Value returned in Redis reply.
67
68typedef struct {
69 fr_value_box_t key; //!< Key value for redis commands
70 fr_value_box_t insert_cmd; //!< Command to run for insert stage, defaults to LPUSH
71 fr_value_box_t insert_arg; //!< Argument to append to insert command
72 fr_value_box_t trim_cmd; //!< Command to run for trim stage, defaults to LTRIM
74
79
81 { FR_CONF_OFFSET("trim_count", rlm_rediswho_t, trim_count), .dflt = "-1" },
82 { FR_CONF_OFFSET_FLAGS("expiry_time", CONF_FLAG_REQUIRED, rlm_rediswho_t, expiry_time) },
83
84 { FR_CONF_POINTER("redis", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = redis_config },
85
87};
88
89static fr_dict_t const *dict_radius;
90static fr_dict_t const *dict_redis;
91
94 { .out = &dict_radius, .proto = "radius" },
95 { .out = &dict_redis, .proto = "redis" },
97};
98
100
103 { .out = &attr_acct_status_type, .name = "Acct-Status-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
105};
106
107/** Process redisReply from rediswho command
108 *
109 * The reply is expected to either be an integer or status.
110 */
111static void rediswho_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
112{
113 rediswho_rctx_t *rediswho_rctx = talloc_get_type_abort(rctx, rediswho_rctx_t);
114
115 switch (reply->type) {
116 case REDIS_REPLY_INTEGER:
117 rediswho_rctx->ret = reply->integer;
118 return;
119
120 case REDIS_REPLY_STATUS:
121 if (strcmp(reply->str, "OK") != 0) {
122 REDEBUG("Redis returned %s", reply->str);
123 rediswho_rctx->ret = -1;
124 return;
125 }
126
127 rediswho_rctx = 0;
128 return;
129
130 default:
131 REDEBUG("Bad result type, expected integer, got %s",
132 fr_table_str_by_value(redis_reply_types, reply->type, "<UNKNOWN>"));
133 rediswho_rctx->ret = -1;
134 return;
135 }
136
137}
138
139/*
140 * Enqueue a Redis command which will return a single integer or status result.
141 */
143 rediswho_rctx_t *rctx, char const *fmt, ...)
144{
145 va_list ap;
147 int cmd_len;
148
149 if (!fmt || !*fmt) return REDIS_ASYNC_RCODE_ERROR;
150
151 /*
152 * If there's a previous formatted command, clean up
153 */
154 if (rctx->cmd_str) {
155 redisFreeCommand(rctx->cmd_str);
156 rctx->cmd_str = NULL;
158 }
159
160 va_start(ap, fmt);
161 cmd_len = redisvFormatCommand(&rctx->cmd_str, fmt, ap);
162 va_end(ap);
163
164 if (cmd_len < 0) {
165 RERROR("Failed formatting redis commmand");
167 }
170
171 rctx->cmd = fr_redis_async_cmd_start(rctx, request, &ret, thread->rtcluster,
172 (uint8_t const *)key->vb_strvalue, key->vb_length, rctx->cmds, false, NULL);
173
174 return ret;
175}
176
177static void mod_accounting_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
178{
179 rediswho_rctx_t *rctx = talloc_get_type_abort(mctx->rctx, rediswho_rctx_t);
180
181 RDEBUG2("Forcibly cancelling Redis command");
182
184}
185
187 fr_redis_async_cmd_t *cmd, module_ctx_t const *mctx,
189{
190 switch (fr_redis_command_set_rcode(cmds)) {
192 {
194 rlm_rediswho_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
195
196 if (inst->conf.use_cluster_map) fr_redis_ct_map_get(thread->rtcluster, thread->cw,
197 inst->coord_pair_reg, false);
198 }
200
203 return unlang_module_yield(request, resume, cancel, ~FR_SIGNAL_CANCEL, mctx->rctx);
204
207 return unlang_module_yield(request, resume, cancel, ~FR_SIGNAL_CANCEL, mctx->rctx);
208
209 default:
210 break;
211 }
213}
214
216 request_t *request)
217{
218 rediswho_rctx_t *rctx = talloc_get_type_abort(mctx->rctx, rediswho_rctx_t);
219
220 if (rediswho_rcode_check(request, rctx->cmds, rctx->cmd, mctx, mod_accounting_resume,
222
223 if (rctx->ret < 0) {
224 RPERROR("Redis command failed");
226 }
227
229}
230
232 request_t *request)
233{
234 rediswho_rctx_t *rctx = talloc_get_type_abort(mctx->rctx, rediswho_rctx_t);
236 rlm_rediswho_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
237 rediswho_call_env_t *env = talloc_get_type_abort(mctx->env_data, rediswho_call_env_t);
239
240 if (rediswho_rcode_check(request, rctx->cmds, rctx->cmd, mctx, mod_accounting_expire,
242
243 if (rctx->ret < 0) {
244 RPERROR("Redis command failed");
246 }
247
248 ret = rediswho_command(thread, request, &env->key, rctx, "EXPIRE %b %d",
249 (uint8_t const *)env->key.vb_strvalue, env->key.vb_length, inst->expiry_time);
250
251 REDIS_ASYNC_START_RCODE_PROCESS(ret, thread->rtcluster, thread->cw, thread->inst->coord_pair_reg,
252 "Failed to enqueue Redis cache find commands", UNLANG_ACTION_FAIL)
253 RDEBUG3("Setting expiry to %d", inst->expiry_time);
254
256}
257
259 request_t *request)
260{
261 rediswho_rctx_t *rctx = talloc_get_type_abort(mctx->rctx, rediswho_rctx_t);
263 rlm_rediswho_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
264 rediswho_call_env_t *env = talloc_get_type_abort(mctx->env_data, rediswho_call_env_t);
266
267 if (rediswho_rcode_check(request, rctx->cmds, rctx->cmd, mctx, mod_accounting_trim,
269
270 if (rctx->ret < 0) {
271 RPERROR("Redis command failed");
273 }
274
275 RDEBUG3("Key \"%pV\" has %d entries", &env->key, rctx->ret);
276
277 if (rctx->ret > inst->trim_count) {
278 ret = rediswho_command(thread, request, &env->key, rctx, "%s %b 0 %d", env->trim_cmd.vb_strvalue,
279 (uint8_t const *)env->key.vb_strvalue, env->key.vb_length, inst->trim_count - 1);
280
281 REDIS_ASYNC_START_RCODE_PROCESS(ret, thread->rtcluster, thread->cw, thread->inst->coord_pair_reg,
282 "Failed to enqueue Redis cache find commands", UNLANG_ACTION_FAIL)
283 RDEBUG3("Trimming \"%pV\" to %d entries", &env->key, inst->trim_count);
285 }
286
287 ret = rediswho_command(thread, request, &env->key, rctx, "EXPIRE %b %d",
288 (uint8_t const *)env->key.vb_strvalue, env->key.vb_length, inst->expiry_time);
289
290 REDIS_ASYNC_START_RCODE_PROCESS(ret, thread->rtcluster, thread->cw, thread->inst->coord_pair_reg,
291 "Failed to enqueue Redis cache find commands", UNLANG_ACTION_FAIL)
292
294}
295
297{
298 if (rctx->cmd_str) redisFreeCommand(rctx->cmd_str);
299 return 0;
300}
301
302static unlang_action_t CC_HINT(nonnull) mod_accounting(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
303{
305 rlm_rediswho_thread_t *thread = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
306 rediswho_call_env_t *env = talloc_get_type_abort(mctx->env_data, rediswho_call_env_t);
308 rediswho_rctx_t *rctx;
309
310 if (env->key.vb_length == 0) {
311 RDEBUG2("Zero length key value");
313 }
314
315 if (env->insert_arg.vb_length == 0) {
316 RDEBUG2("Zero length argument value");
318 }
319
320 MEM(rctx = talloc(unlang_interpret_frame_talloc_ctx(request), rediswho_rctx_t));
321 *rctx = (rediswho_rctx_t) { .ret = -1 };
322 rctx->cmds = fr_redis_command_set_alloc(rctx, request, NULL, NULL, NULL, false);
323 talloc_set_destructor(rctx, _rediswho_rctx_free);
324
325 ret = rediswho_command(thread, request, &env->key, rctx, "%s %b %b", env->insert_cmd.vb_strvalue,
326 (uint8_t const *)env->key.vb_strvalue, env->key.vb_length,
327 (uint8_t const *)env->insert_arg.vb_strvalue, env->insert_arg.vb_length);
328
329 REDIS_ASYNC_START_RCODE_PROCESS(ret, thread->rtcluster, thread->cw, thread->inst->coord_pair_reg,
330 "Failed to enqueue Redis cache find commands", UNLANG_ACTION_FAIL)
331
332 return unlang_module_yield(request, inst->trim_count > 0 ? mod_accounting_trim : mod_accounting_expire,
333 mod_accounting_cancel, ~FR_SIGNAL_CANCEL, rctx);
334}
335
337{
338 rlm_rediswho_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
339 rlm_rediswho_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_rediswho_t);
340
341 t->rtcluster = fr_redis_ct_alloc(t, inst->tls_conf, mctx->el, &inst->conf, NULL, NULL, false);
342
343 if (!t->rtcluster) return -1;
344 t->inst = inst;
345
346 return 0;
347}
348
350{
351 rlm_rediswho_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
352 rlm_rediswho_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_rediswho_t);
353
354 t->cw = fr_coord_attach(t, mctx->el, inst->coord_reg);
355
356 if (!t->cw) {
357 ERROR("Failed to attach to coordinator");
358 return -1;
359 }
360
361 if ((inst->conf.trunk_conf.start == 0) || (fr_schedule_worker_id() != 0)) return 0;
362
363 return fr_redis_ct_map_bootstrap(t->rtcluster, t->cw, inst->coord_pair_reg);
364}
365
367
368static int mod_instantiate(module_inst_ctx_t const *mctx)
369{
370 rlm_rediswho_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_rediswho_t);
371 CONF_SECTION *subcs = cf_section_find(mctx->mi->conf, "redis", NULL);
372
373 inst->conf.log_prefix = mctx->mi->name;
374 inst->conf.module_name = mctx->mi->module->name;
375 inst->conf.inst_name = mctx->mi->name;
376
377 if (inst->conf.use_tls) {
378 inst->tls_conf = cf_section_find(subcs, "tls", CF_IDENT_ANY);
379
380 if (!inst->tls_conf) {
381 cf_log_err(mctx->mi->conf, "Missing tls section");
382 return -1;
383 }
384 }
385
386 if (!inst->conf.use_cluster_map) return 0;
387
388 if (inst->conf.database) {
389 cf_log_err(mctx->mi->conf, "Cannot set Redis database number when cluster in use");
390 return -1;
391 }
392
394 .name = mctx->mi->name,
395 .worker_cb = worker_pair_callbacks,
396 .cb_id = REDIS_COORD_PAIR_CALLBACK_ID,
397 .root = fr_dict_root(dict_redis),
398 .cs = subcs,
399 }
400 );
401 if (!inst->coord_pair_reg) return -1;
402
403 FR_COORD_PAIR_CB_CTX_SET(coord_callbacks, worker_callbacks, inst->coord_pair_reg);
404
406 .name = mctx->mi->name,
407 .coord_cb = coord_callbacks,
408 .worker_cb = worker_callbacks,
409 .mi = mctx->mi
410 });
411
412 if (!inst->coord_reg) return -1;
413
414 return 0;
415}
416
418{
419 rlm_rediswho_thread_t *t = talloc_get_type_abort(mctx->thread, rlm_rediswho_thread_t);
420
421 if (!t->cw) return 0;
422
423 fr_coord_detach(t->cw, true);
424 t->cw = NULL;
425 return 0;
426}
427
428static int mod_detach(module_detach_ctx_t const *mctx)
429{
430 rlm_rediswho_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_rediswho_t);
431
432 fr_coord_deregister(inst->coord_reg);
433 talloc_free(inst->coord_pair_reg);
434 return 0;
435}
436
437static int mod_load(void)
438{
440
441 return 0;
442}
443
451
452static int redis_command_call_env_parse(TALLOC_CTX *ctx, call_env_parsed_head_t *out, tmpl_rules_t const *t_rules,
453 CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
454{
455 CONF_SECTION const *subcs = NULL;
456 char *section2, *p;
457
459
460 section2 = talloc_strdup(NULL, section_name_str(cec->asked->name2));
461 p = section2;
462 while (*p != '\0') {
463 *(p) = tolower((uint8_t)*p);
464 p++;
465 }
467 talloc_free(section2);
468 if (!subcs) {
469 cf_log_warn(ci, "No \"%s\" section found", section_name_str(cec->asked->name2) );
470 return 0;
471 }
472
473 return call_env_parse(ctx, out, cec->asked->name2, t_rules, subcs, cec, rediswho_env_parser);
474}
475
483
486 .common = {
487 .magic = MODULE_MAGIC_INIT,
488 .name = "rediswho",
489 .inst_size = sizeof(rlm_rediswho_t),
491 .onload = mod_load,
492 .instantiate = mod_instantiate,
493 .coord_attach = mod_coord_attach,
494 .detach = mod_detach,
496 .thread_instantiate = mod_thread_instantiate,
497 .thread_detach = mod_thread_detach,
498 },
499 .method_group = {
500 .bindings = (module_method_binding_t[]){
501 { .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting, .method_env = &method_env },
503 }
504 }
505};
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:37
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:41
va_end(args)
static int const char * fmt
Definition acutest.h:573
va_start(args, fmt)
#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:669
#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:429
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition cf_parse.h:423
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:606
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:1204
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition cf_util.c:695
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:345
#define cf_parent(_cf)
Definition cf_util.h:118
#define cf_log_warn(_cf, _fmt,...)
Definition cf_util.h:346
#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_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.
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:662
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:623
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:2637
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
#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:994
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:479
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:249
int fr_redis_command_set_clear(fr_redis_command_set_t *cmds)
Definition pipeline.c:1036
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:143
fr_redis_async_rcode_t
Definition base.h:80
@ REDIS_ASYNC_RCODE_MOVE
Attempt operation on an alternative node with remap.
Definition base.h:88
@ REDIS_ASYNC_RCODE_ERROR
Unrecoverable error.
Definition base.h:82
@ REDIS_ASYNC_RCODE_ASK
Attempt operation on an alternative node.
Definition base.h:87
@ REDIS_ASYNC_RCODE_TRY_AGAIN
Try the operation again.
Definition base.h:86
@ REDIS_ASYNC_RCODE_SUCCESS
Operation was successful.
Definition base.h:81
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:114
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.
Definition schedule.c:110
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:258
char const * name
Instance name e.g. user_database.
Definition module.h:357
CONF_SECTION * conf
Module's instance configuration.
Definition module.h:351
size_t inst_size
Size of the module's instance data.
Definition module.h:212
void * data
Module's instance data.
Definition module.h:293
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:336
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
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1030