26#include <freeradius-devel/redis/base.h>
27#include <freeradius-devel/util/debug.h>
28#include <freeradius-devel/util/value.h>
32 {
L(
"array"), REDIS_REPLY_ARRAY },
33 {
L(
"error"), REDIS_REPLY_ERROR },
34 {
L(
"integer"), REDIS_REPLY_INTEGER },
35 {
L(
"nil"), REDIS_REPLY_NIL },
36 {
L(
"status"), REDIS_REPLY_STATUS },
37 {
L(
"string"), REDIS_REPLY_STRING }
109 INFO(
"libfreeradius-redis: libhiredis version: %i.%i.%i", HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH);
115 PERROR(
"%s", __FUNCTION__);
119 PERROR(
"%s", __FUNCTION__);
159 switch (reply->type) {
160 case REDIS_REPLY_ERROR:
168 case REDIS_REPLY_STATUS:
172 case REDIS_REPLY_STRING:
176 case REDIS_REPLY_INTEGER:
180 case REDIS_REPLY_NIL:
184 case REDIS_REPLY_ARRAY:
186 for (i = 0; i < reply->elements; i++) {
224 bool box_error,
bool shallow)
236 switch (reply->type) {
237 case REDIS_REPLY_NIL:
246 case REDIS_REPLY_INTEGER:
247 if (reply->integer < INT32_MIN) {
250 else if (reply->integer < INT16_MIN) {
253 else if (reply->integer < INT8_MIN) {
256 else if (reply->integer < 0) {
259 else if (reply->integer > UINT32_MAX) {
262 else if (reply->integer > UINT16_MAX) {
273#if HIREDIS_MAJOR >= 1
274 case REDIS_REPLY_DOUBLE:
279 case REDIS_REPLY_BOOL:
284 case REDIS_REPLY_ERROR:
292#if HIREDIS_MAJOR >= 1
293 case REDIS_REPLY_BIGNUM:
295 case REDIS_REPLY_STRING:
296 case REDIS_REPLY_STATUS:
303 reply->str, reply->len,
true) < 0)
return -1;
307#if HIREDIS_MAJOR >= 1
308 case REDIS_REPLY_VERB:
320 fr_value_box_list_insert_head(&
out->vb_group, verb);
329 fr_value_box_list_insert_head(&
out->vb_group, vtype);
335#if HIREDIS_MAJOR >= 1
336 case REDIS_REPLY_SET:
337 case REDIS_REPLY_MAP:
338 case REDIS_REPLY_PUSH:
340 case REDIS_REPLY_ARRAY:
347 for (i = 0; i < reply->elements; i++) {
351 fr_value_box_list_talloc_free(&
out->vb_group);
356 FR_TYPE_VOID, NULL, box_error, shallow) < 0)
goto array_error;
357 fr_value_box_list_insert_tail(&
out->vb_group, vb);
382 redisReply *key, redisReply *op, redisReply *
value)
387 if (key->type != REDIS_REPLY_STRING) {
388 REDEBUG(
"Bad key type, expected string, got %s",
395 if (op->type != REDIS_REPLY_STRING) {
396 REDEBUG(
"Bad op type, expected string, got %s",
401 RDEBUG3(
"Got key : %s", key->str);
402 RDEBUG3(
"Got op : %s", op->str);
409 .dict_def = request->local_dict,
410 .list_def = request_attr_request
420 REDEBUG(
"Invalid operator \"%s\"", op->str);
424 switch (
value->type) {
425 case REDIS_REPLY_STRING:
426 case REDIS_REPLY_INTEGER:
433 RPEDEBUG(
"Failed converting Redis data");
443 REDEBUG(
"Bad value type, expected string or integer, got %s",
450 map_list_insert_tail(
out, map);
490 "bytes, got %zu bytes", (
size_t)(slen * -1));
519 out_len[0] = key_len;
521 out_len[1] = strlen(
out[1]);
539 if (reply->type != REDIS_REPLY_STRING) {
571 char const *p = version;
574 num = strtoul(p, &q, 10);
580 if ((p == q) || (q[0] !=
'.')) {
587 num = strtoul(p, &q, 10);
593 if ((p == q) || (q[0] !=
'.')) {
600 num = strtoul(p, &q, 10);
601 if (num > UINT16_MAX) {
606 if ((p == q) || (q[0] !=
'\0')) {
#define L(_str)
Helper for initialising arrays of string literals.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define fr_dict_autofree(_to_free)
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.
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
#define fr_dict_autoload(_to_load)
#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 REXDENT()
Exdent (unindent) R* messages by one level.
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
#define RDEBUGX(_l, fmt,...)
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
#define RPEDEBUG(fmt,...)
#define DEBUGX(_lvl, _fmt,...)
#define RINDENT()
Indent R* messages by one level.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
size_t fr_sbuff_out_bstrncpy_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
fr_slen_t tmpl_print(fr_sbuff_t *out, tmpl_t const *vpt, fr_sbuff_escape_rules_t const *e_rules)
fr_redis_rcode_t
Codes are ordered inversely by priority.
@ REDIS_RCODE_RECONNECT
Transitory error, caller should retry the operation with a new connection.
@ REDIS_RCODE_SUCCESS
Operation was successful.
@ REDIS_RCODE_MOVE
Attempt operation on an alternative node with remap.
@ REDIS_RCODE_TRY_AGAIN
Try the operation again.
@ REDIS_RCODE_ASK
Attempt operation on an alternative node.
@ REDIS_RCODE_ERROR
Unrecoverable library/server error.
fr_dict_attr_t const * attr_redis_node_role
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.
fr_dict_autoload_t redis_base_dict[]
static int _redis_dict_free(UNUSED void *uctx)
fr_table_num_sorted_t const redis_rcodes[]
int fr_redis_reply_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, redisReply *reply, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, bool box_error, bool shallow)
Convert a string or integer type to fr_value_box_t of specified type.
int redis_dict_init(void)
Load the Redis dictionaries.
fr_dict_attr_t const * attr_redis_bootstrap_node
fr_dict_attr_t const * attr_redis_use_tls
int fr_redis_tuple_from_map(TALLOC_CTX *pool, char const *out[], size_t out_len[], map_t *map)
Add a single map pair to an existing command string as three elements.
fr_dict_attr_t const * attr_redis_slot_end
fr_dict_attr_t const * attr_redis_force_update
size_t redis_reply_types_len
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
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
uint32_t fr_redis_version_num(char const *version)
Convert version string into a 32bit unsigned integer for comparisons.
fr_dict_t const * dict_redis
fr_table_num_sorted_t const redis_reply_types[]
fr_dict_attr_t const * attr_redis_slot_start
fr_dict_attr_t const * attr_redis_max_nodes
fr_dict_attr_autoload_t redis_base_dict_attr[]
int 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.
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
static int _redis_dict_init(UNUSED void *uctx)
fr_dict_attr_t const * attr_redis_shard
int fr_redis_reply_to_map(TALLOC_CTX *ctx, map_list_t *out, request_t *request, redisReply *key, redisReply *op, redisReply *value)
Convert a pair of redis reply objects to a map.
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
#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)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define tmpl_value_length(_tmpl)
#define tmpl_value(_tmpl)
int tmpl_afrom_value_box(TALLOC_CTX *ctx, tmpl_t **out, fr_value_box_t *data, bool steal)
Create a tmpl_t from a fr_value_box_t.
#define tmpl_is_attr(vpt)
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, tmpl_attr_error_t *err, tmpl_t **out, char const *name, tmpl_rules_t const *rules))
Parse a string into a TMPL_TYPE_ATTR_* type tmpl_t.
#define tmpl_is_data(vpt)
#define tmpl_value_type(_tmpl)
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Optional arguments passed to vp_tmpl functions.
fr_token_t op
The operator that controls insertion of the dst attribute.
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in a lexicographically sorted array of name to num mappings.
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
fr_table_num_ordered_t const fr_tokens_table[]
char const * fr_strerror(void)
Get the last library error.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
#define fr_box_strvalue_len(_val, _len)
#define fr_value_box_init_null(_vb)
Initialise an empty/null box that will be filled later.
#define fr_value_box(_box, _var, _tainted)
Automagically fill in a box, determining the value type from the type of the C variable.
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
static size_t char ** out