24#include <freeradius-devel/redis/attrs.h>
25#include <freeradius-devel/redis/base.h>
26#include <freeradius-devel/redis/cluster_async.h>
27#include <freeradius-devel/io/coord_pair.h>
28#include <freeradius-devel/server/main_config.h>
29#include <freeradius-devel/unlang/function.h>
30#include <freeradius-devel/unlang/interpret.h>
31#include <freeradius-devel/util/debug.h>
105 if (ret != 0)
return ret;
185#define FR_REDIS_PACKET_CODE_VALID(_code) (((_code) > 0) && ((_code) < FR_REDIS_CODE_MAX))
186#define FR_REDIS_PROCESS_CODE_VALID(_code) (FR_REDIS_PACKET_CODE_VALID(_code) || (_code == FR_REDIS_DO_NOT_RESPOND))
188#define PROCESS_PACKET_TYPE fr_redis_packet_code_t
189#define PROCESS_CODE_MAX FR_REDIS_CODE_MAX
190#define PROCESS_CODE_DO_NOT_RESPOND FR_REDIS_DO_NOT_RESPOND
191#define PROCESS_PACKET_CODE_VALID FR_REDIS_PROCESS_CODE_VALID
192#define PROCESS_INST process_redis_t
193#define PROCESS_RCTX process_redis_rctx_t
195#include <freeradius-devel/server/process.h>
216 if (reply->type != REDIS_REPLY_ARRAY)
return -1;
217 if (reply->elements == 0)
return 0;
218 if ((reply->elements % 2) != 0)
return -1;
219 for (i = 0; i < reply->elements; i++)
if (reply->element[i]->type != REDIS_REPLY_INTEGER)
return -1;
221 for (i = 0; i < (reply->elements - 1); i += 2) {
226 if (reply->element[i]->type != REDIS_REPLY_INTEGER)
return -1;
227 if (reply->element[i]->integer >=
KEY_SLOTS)
return -1;
228 vp->vp_uint16 = (
uint16_t) reply->element[i]->integer;
232 if (reply->element[i + 1]->type != REDIS_REPLY_INTEGER)
return -1;
233 vp->vp_uint16 = (
uint16_t) reply->element[i + 1]->integer;
234 if (reply->element[i + 1]->integer >=
KEY_SLOTS)
return -1;
237 for(s = reply->element[i]->integer; s <= reply->element[i + 1]->integer; s++) slots_covered[s] =
true;
255 redisReply *node, *field, *
value;
260 if (reply->type != REDIS_REPLY_ARRAY)
return -1;
261 for (i = 0; i < reply->elements; i++)
if (reply->element[i]->type != REDIS_REPLY_ARRAY)
return -1;
263 for (i = 0; i < reply->elements; i++) {
264 node = reply->element[i];
269 for (j = 0; j < node->elements; j += 2)
if (node->element[j]->type != REDIS_REPLY_STRING)
return -1;
273 for (j = 0; j < (node->elements - 1); j +=2) {
274 field = node->element[j];
275 value = node->element[j + 1];
276 if (strcmp(field->str,
"endpoint") == 0) {
277 if (
value->type != REDIS_REPLY_STRING)
return -1;
281 }
else if (strcmp(field->str,
"port") == 0) {
282 if (
value->type != REDIS_REPLY_INTEGER)
return -1;
286 }
else if (strcmp(field->str,
"role") == 0) {
287 if (
value->type != REDIS_REPLY_STRING)
return -1;
289 vp->vp_uint8 = (strcmp(
value->str,
"master") == 0) ? 1 : 2;
291 }
else if (strcmp(field->str,
"health") == 0) {
292 if (
value->type != REDIS_REPLY_STRING)
return -1;
293 if (strcmp(
value->str,
"failed") == 0) {
294 TALLOC_FREE(node_vp);
306 if (!node_vp)
continue;
365 if(reply->type != REDIS_REPLY_ARRAY)
return -1;
369 memset(slots_covered, 0,
sizeof(slots_covered));
371 for (i = 0; i < reply->elements; i++) {
373 redisReply *shard = reply->element[i];
375 if (shard->type != REDIS_REPLY_ARRAY) {
380 if (shard->elements < 4 || (shard->elements % 2 != 0))
goto error;
385 for (j = 0; j < (shard->elements - 1); j += 2) {
386 redisReply *field = shard->element[j];
387 if (strcmp(field->str,
"slots") == 0) {
390 if (ret < 0)
goto error;
403 }
else if (strcmp(field->str,
"nodes") == 0) {
405 if (ret < 0)
goto error;
406 if (ret == 0)
goto clean_up;
414 for (s = 0; s <
KEY_SLOTS; s++)
if (!slots_covered[s])
goto error;
457 if(reply->type != REDIS_REPLY_ARRAY)
return -1;
461 memset(slots_covered, 0,
sizeof(slots_covered));
470 for (i = 0; i < reply->elements; i++) {
472 redisReply *map = reply->element[i];
481 if (map->element[0]->type != REDIS_REPLY_INTEGER) {
488 if (map->element[0]->integer >=
KEY_SLOTS)
goto error;
489 vp->vp_uint16 = (
uint16_t) map->element[0]->integer;
493 if (map->element[1]->type != REDIS_REPLY_INTEGER)
goto error;
494 if (map->element[0]->integer >=
KEY_SLOTS)
goto error;
495 vp->vp_uint16 = (
uint16_t) map->element[1]->integer;
498 for (j = 2; j < map->elements; j++) {
499 node = map->element[j];
504 if (node->element[0]->type != REDIS_REPLY_STRING)
goto error;
509 if (node->element[1]->type != REDIS_REPLY_INTEGER)
goto error;
510 vp->vp_uint16 = (
uint16_t) node->element[1]->integer;
514 vp->vp_uint8 = (j == 2) ? 1 : 2;
518 for (s = map->element[0]->integer; s <= map->element[1]->integer; s++) slots_covered[s] =
true;
523 for (s = 0; s <
KEY_SLOTS; s++)
if (!slots_covered[s])
goto list_free;
538 .username =
conf->username,
539 .use_tls =
conf->use_tls,
542 host_vp->vp_length, AF_UNSPEC,
true,
true) < 0){
549 if (!port_vp)
goto error;
557 if (
conf->trunk_conf.conn_triggers) {
560 .module =
"process_redis",
561 .name = inst->inst_name, \
563 .port = node->io_conf.port \
571 redisReply *reply,
void *rctx)
589 if (reply->type != REDIS_REPLY_STRING) {
590 RERROR(
"Bad value type, expected string, got %s",
599 RERROR(
"Response did not contain cluster_state");
615 fr_sbuff_set_to_start(&sbuff);
618 RERROR(
"Response did not contain cluster_current_epoch");
624 RERROR(
"Failed parsing current_cluster_epoch");
645 RDEBUG2(
"Cluster map fetched:");
669 TALLOC_CTX *local = talloc_new(NULL);
672 DEBUG2(
"Retrying fetch of cluster map");
674 DEBUG2(
"Refreshing cluster map");
723 RDEBUG2(
"Fetching cluster map %d from %s:%d", cluster->
cluster_id, node->io_conf.hostname,
739 RERROR(
"Unable to enqueue request on node %s:%d", node->io_conf.hostname,
752 RERROR(
"Unable to query any cluster node");
757 RERROR(
"Failed setting up retry event");
769 size_t completed = 0;
778 switch (nrctx->status) {
796 RWARN(
"Node %s:%d returned lower epoch than other nodes - ignoring",
797 nrctx->node->io_conf.hostname, nrctx->node->io_conf.port);
815 RERROR(
"Unable to enqueue request on node %s:%d",
816 nrctx->node->io_conf.hostname, nrctx->node->io_conf.port);
823 RWARN(
"Node %s:%d didn't return a cluster", nrctx->node->io_conf.hostname,
824 nrctx->node->io_conf.port);
841 RERROR(
"No node returned a valid cluster map");
846 RERROR(
"Failed setting up retry event");
867 node->in_cluster =
false;
879 if ((strcmp(node->io_conf.hostname, endpoint->vp_strvalue) == 0) &&
880 (node->io_conf.port == port->vp_uint16)) {
881 node->in_cluster =
true;
890 RERROR(
"Failed adding new node to cluster");
899 if (node->in_cluster)
continue;
927 RERROR(
"Failed setting up refresh event");
948 if (!nrctx->cmds)
continue;
949 RWARN(
"Forcibly cancelling cluster map request on %s:%d",
950 nrctx->node->io_conf.hostname, nrctx->node->io_conf.port);
960 if (!node->
trunk)
continue;
973 if (!pending)
return;
1015 AF_UNSPEC,
true,
true) < 0) {
1019 if (find.
port == 0) {
1021 find.
port = port_vp->vp_uint16;
1035 "Max nodes (%d) mis-match with existing cluster configured with %d",
1056 RDEBUG2(
"Cluster map already being fetched");
1079 conf->trunk_conf =
inst->trunk_conf;
1091 conf->max_nodes =
vp->vp_uint8;
1092 conf->use_cluster_map =
true;
1108 conf->use_tls =
true;
1159 RWARN(
"Cluster was updated less than a second ago, returning last response");
1169 fr_process_state_t
const *
state;
1179 request->component =
"redis";
1180 request->module = NULL;
1183 UPDATE_STATE(packet);
1186 REDEBUG(
"Invalid packet type (%u)", request->packet->code);
1193 return state->recv(p_result, mctx, request);
1226 .recv = recv_cluster_map_bootstrap,
1231 .recv = recv_cluster_map_get,
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ 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 char buffer[256]
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
#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_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Defines a CONF_PAIR to C data type mapping.
A section grouping multiple CONF_PAIR.
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.
Thread local state for a cluster.
#define KEY_SLOTS
Maximum number of keyslots (should not change).
int fr_coord_to_worker_reply_broadcast(request_t *request)
Send a reply list from a coordinator to all workers.
int fr_coord_to_worker_reply_send(request_t *request, uint32_t worker_id)
Send a reply list from a coordinator to a worker.
fr_coord_pair_t * fr_coord_pair_request_coord_pair(request_t *request)
Return the coord_pair associated with a coord_pair internal request.
int fr_coord_pair_coord_request_start(fr_coord_pair_t *coord_pair, fr_pair_list_t *list, fr_time_t now)
Start a coordinator request to run through a coord_pair process module.
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_fatal_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
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.
#define fr_dlist_foreach(_list_head, _type, _iter)
Iterate over the contents of a list.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Head of a doubly linked list.
Entry in a doubly linked list.
#define unlang_function_push_with_result(_result_p, _request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack that produces a result.
#define unlang_function_repeat_set(_request, _repeat)
Set a new repeat function for an existing function frame.
int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
char * fr_inet_ntop(char out[static FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print the address portion of a fr_ipaddr_t.
fr_cmp_ret_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
#define FR_IPADDR_STRLEN
Like INET6_ADDRSTRLEN but includes space for the textual Zone ID.
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
static fr_dict_t const * dict_freeradius
fr_dict_attr_t const * attr_packet_type
fr_dict_attr_t const * attr_redis_node_role
fr_dict_attr_t const * attr_redis_bootstrap_node
fr_dict_attr_t const * attr_redis_use_tls
fr_dict_attr_t const * attr_redis_slot_end
fr_dict_attr_t const * attr_redis_force_update
fr_dict_attr_t const * attr_redis_packet_type
fr_dict_attr_t const * attr_redis_log_prefix
fr_dict_attr_t const * attr_redis_node
fr_dict_attr_t const * attr_redis_node_port
fr_dict_attr_t const * attr_redis_slot
fr_dict_t const * dict_redis
fr_dict_attr_t const * attr_redis_slot_start
fr_dict_attr_t const * attr_redis_max_nodes
fr_dict_attr_t const * attr_redis_password
fr_dict_attr_t const * attr_redis_bootstrap_port
fr_dict_attr_t const * attr_redis_cluster_id
fr_dict_attr_t const * attr_redis_tls_conf
fr_dict_attr_t const * attr_redis_username
fr_dict_attr_t const * attr_redis_node_endpoint
fr_dict_attr_t const * attr_redis_shard
char const * password
to authenticate to Redis.
#define REXDENT()
Exdent (unindent) R* messages by one level.
#define RINDENT()
Indent R* messages by one level.
Stores all information relating to an event list.
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
@ FR_TYPE_INT32
32 Bit signed integer.
fr_cmp_ret_t
Result of an ordering comparison.
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.
void * thread
Thread instance data.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
Temporary structure to hold arguments for thread_instantiation calls.
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
int fr_pair_prepend_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and prepend)
fr_redis_pipeline_status_t redis_command_set_enqueue(fr_redis_trunk_t *rtrunk, fr_redis_command_set_t *cmds)
Enqueue a command set on a specific trunk.
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.
void fr_redis_command_set_cancel(fr_redis_command_set_t *cmds)
Cancel a command set.
fr_redis_pipeline_status_t fr_redis_command_literal_add(fr_redis_command_set_t *cmds, char const *cmd_str, fr_redis_command_complete_t complete, void *rctx)
Add a literal command to the command set.
fr_redis_trunk_t * fr_redis_trunk_alloc(fr_redis_ct_t *rtcluster, fr_redis_io_conf_t const *io_conf, fr_pair_list_t *trigger_args, fr_redis_trunk_active_t active, void *active_uctx, bool active_oneshot)
Allocate a new trunk.
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 unlang_action_t mod_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static fr_process_state_t const process_state[]
RECV(for_any_server)
Validate a solicit/rebind/confirm message.
static int mod_load(void)
static int mod_instantiate(module_inst_ctx_t const *mctx)
static const conf_parser_t config[]
int32_t worker_id
The worker which sent the data leading to this request.
bool in_cluster
Has the node been found in the latest cluster map.
static unlang_action_t process_redis_return_existing(request_t *request, process_redis_cluster_t *cluster, uint32_t worker_id)
uint64_t current_epoch
Redis cluster epoch as reported by this node.
static void redis_cluster_map_get_timeout(UNUSED fr_timer_list_t *el, UNUSED fr_time_t now, void *uctx)
bool cluster_ok
Does CLUSTER INFO say the cluster is OK.
static void redis_cluster_info_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
uint16_t port
Port of the first bootstrap server.
bool fetching
The map is being fetched.
static const uint32_t redis_shards_version
static uint16_t cluster_id
static int _process_redis_cluster_free(process_redis_cluster_t *cluster)
map_get_status_t status
Status of the node calls.
fr_rb_node_t cluster_by_id
Entry in the tree of clusters by ID.
uint64_t cluster_epoch
Largest epoch value returned by any node.
process_redis_node_t * current_node
Node currently being queried.
process_redis_t const * inst
Module instance.
static int fr_redis_cluster_shards_nodes_to_pairs(redisReply *reply, fr_pair_t *shard_vp)
Convert the "nodes" array in CLUSTER SHARDS replies into pairs.
fr_coord_pair_t * coord_pair
The coord_pair which requested this cluster map.
static void redis_cluster_slots_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
fr_dlist_head_t nodes
List of current nodes in the cluster.
fr_redis_trunk_t * trunk
Trunk connection for this node.
static unlang_action_t process_redis_return_failed(request_t *request, process_redis_cluster_t *cluster, uint32_t worker_id)
Send a Cluster-Failed message to a worker.
static void process_redis_pending_cancel(module_ctx_t const *mctx, request_t *request, UNUSED fr_signal_t action)
#define FR_REDIS_PACKET_CODE_VALID(_code)
uint32_t version
Redis version on this node.
fr_dlist_t entry
In list of resume contexts.
fr_timer_t * ev
Timeout event for this node.
fr_redis_ct_t * rtcluster
Cluster used to allocate redis trunk connections.
fr_dlist_t entry
Entry in the list of cluster nodes.
static fr_cmp_ret_t process_redis_pending_cmp(void const *a, void const *b)
fr_rb_tree_t pending
Requests waiting for custer map update.
fr_redis_command_set_t * cmds
Command set for fetching cluster map.
static fr_dict_attr_t const * attr_worker_id
static fr_cmp_ret_t cluster_server_cmp(void const *a, void const *b)
fr_process_module_t process_redis
process_redis_cluster_t * cluster
Cluster which is being updated.
bool failed
Has the cluster failed.
static void redis_cluster_map_get_cancel(request_t *request, UNUSED fr_signal_t action, void *uctx)
fr_time_t last_update
When was the map last updated.
fr_time_delta_t retry_interval
fr_redis_io_conf_t io_conf
Connection config for this node.
static unlang_action_t redis_cluster_map_get(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
uint16_t cluster_id
Numeric ID assigned by the coordinator.
fr_time_delta_t refresh_interval
fr_redis_conf_t * conf
Redis config for this cluster.
static fr_cmp_ret_t cluster_id_cmp(void const *a, void const *b)
static int process_redis_cluster_node_add(TALLOC_CTX *ctx, process_redis_cluster_t *cluster, process_redis_t const *inst, fr_redis_conf_t *conf, fr_pair_t *host_vp, fr_pair_t *port_vp)
static void redis_cluster_info_server_results(request_t *request, UNUSED fr_redis_command_t *cmd, redisReply *reply, void *rctx)
fr_rb_node_t cluster_by_server
Entry in the tree of clusters by bootstrap server.
fr_dict_attr_autoload_t process_redis_dict_attr[]
fr_pair_list_t cluster_pairs
Pairs built from the last fetch.
process_redis_sections_t sections
module_method_t const * method
process_redis_node_t * node
Node being queried.
fr_timer_t * ev
Timer event for retry / refresh.
static unlang_action_t redis_cluster_map_get_resume(UNUSED unlang_result_t *p_result, request_t *request, void *uctx)
static int fr_redis_cluster_shards_to_pairs(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *list, redisReply *reply)
Convert the reply to CLUSTER SHARDS into pairs.
map_get_status_t
State of cluster map fetching from each node.
@ CLUSTER_MAP_GET_TIMEOUT
fr_pair_list_t list
To populate with parsed reply data.
unlang_result_t result
Where results are written to.
process_redis_thread_t * thread
Thread instance.
fr_rb_tree_t cluster_by_id
Tree of clusters by ID.
fr_ipaddr_t addr
IP address of the first bootstrap server.
fr_pair_list_t trigger_args
Pair list to pass to trigger.
fr_dict_autoload_t process_redis_dict[]
fr_dlist_head_t rctx_list
List of per-node resume contexts.
CONF_SECTION * cluster_map_get
fr_rb_tree_t cluster_by_server
Tree of clusters by primary bootstrap server.
static void redis_cluster_map_get_refetch(UNUSED fr_timer_list_t *tl, fr_time_t now, void *uctx)
static int fr_redis_cluster_slots_to_pairs(TALLOC_CTX *ctx, request_t *request, fr_pair_list_t *list, redisReply *reply)
Convert the reply to CLUSER SLOTS into pairs.
static int fr_redis_cluster_shards_slots_to_pairs(redisReply *reply, fr_pair_t *shard_vp, bool slots_covered[KEY_SLOTS])
Convert the "slots" array in CLUSTER SHARDS replies into pairs.
Coordinator representation of a Redis cluster.
Resume context for node specific calls.
Resume context for Redis requests.
#define PROCESS_TRACE
Trace each state function as it's entered.
module_t common
Common fields for all loadable modules.
Common public symbol definition for all process modules.
#define RDEBUG_ENABLED2()
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
int fr_rb_remove(void **removed, fr_rb_tree_t *tree, void const *data)
Remove an entry from the tree, without freeing the data.
int fr_rb_find(void **found, fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
void * fr_rb_iter_init_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Initialise an in-order iterator.
void fr_rb_iter_delete_inorder(fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Remove the current node from the tree.
int fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
void * fr_rb_iter_next_inorder(UNUSED fr_rb_tree_t *tree, fr_rb_iter_inorder_t *iter)
Return the next node.
#define fr_rb_inline_init(_tree, _type, _field, _data_cmp, _data_free)
Initialises a red black tree.
Iterator structure for in-order traversal of an rbtree.
The main red black tree structure.
#define RETURN_UNLANG_FAIL
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
void fr_redis_reply_print(fr_log_lvl_t lvl, redisReply *reply, request_t *request, int idx, fr_redis_rcode_t status)
Print the response data in a useful treelike form.
#define REDIS_VERSION(_max, _min, _patch)
uint8_t max_nodes
Maximum number of cluster nodes to connect to.
fr_redis_rcode_t fr_redis_parse_version(char *out, size_t out_len, redisReply *reply)
Parse the reply from the Redis command INFO SERVER to extract the version.
int redis_dict_init(void)
Load the Redis dictionaries.
uint32_t fr_redis_version_num(char const *version)
Convert version string into a 32bit unsigned integer for comparisons.
@ FR_REDIS_CLUSTER_MAP_BOOTSTRAP
@ FR_REDIS_CLUSTER_MAP_GET
@ FR_REDIS_CLUSTER_MAP_UPDATE
@ FR_REDIS_CLUSTER_MAP_FAIL
fr_table_num_sorted_t const redis_reply_types[]
@ REDIS_RCODE_SUCCESS
Operation was successful.
Configuration parameters for a redis connection.
static int mod_thread_instantiate(module_thread_inst_ctx_t const *mctx)
#define fr_sbuff_adv_past_str_literal(_sbuff, _needle)
#define fr_sbuff_adv_to_str_literal(_sbuff, _len, _needle)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_init_in(_out, _start, _len_or_end)
static _Thread_local int worker_id
Internal ID of the current worker thread.
#define MODULE_THREAD_INST(_ctype)
char const * name
Instance name e.g. user_database.
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_RCTX(_ctype)
#define MODULE_INST(_ctype)
conf_parser_t const * config
How to convert a CONF_SECTION to a module instance.
fr_signal_t
Signals that can be generated/processed by request signal handlers.
@ FR_SIGNAL_CANCEL
Request has been cancelled.
static char buff[sizeof("18446744073709551615")+3]
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
Stores an attribute, a value and various bits of other data.
#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)
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
#define fr_time_wrap(_time)
#define fr_time_delta_ispos(_a)
#define fr_time_gt(_a, _b)
A time delta, a difference in time measured in nanoseconds.
static bool fr_timer_armed(fr_timer_t *ev)
int module_trigger_args_build(TALLOC_CTX *ctx, fr_pair_list_t *list, CONF_SECTION const *cs, module_trigger_args_t *args)
Build trigger args pair list for modules.
Common values used by modules when building trigger args.
conf_parser_t const trunk_config[]
Config parser definitions to populate a trunk_conf_t.
Common configuration parameters for a trunk.
static fr_event_list_t * el
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
#define fr_pair_list_append_by_da(_ctx, _vp, _list, _attr, _val, _tainted)
Append a pair to a list, assigning its value.
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.