26 #include <freeradius-devel/redis/base.h>
27 #include <freeradius-devel/util/debug.h>
28 #include <freeradius-devel/util/value.h>
31 {
L(
"array"), REDIS_REPLY_ARRAY },
32 {
L(
"error"), REDIS_REPLY_ERROR },
33 {
L(
"integer"), REDIS_REPLY_INTEGER },
34 {
L(
"nil"), REDIS_REPLY_NIL },
35 {
L(
"status"), REDIS_REPLY_STATUS },
36 {
L(
"string"), REDIS_REPLY_STRING }
55 INFO(
"libfreeradius-redis: libhiredis version: %i.%i.%i", HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH);
75 if (!reply)
switch (conn->
handle->err) {
86 case REDIS_ERR_PROTOCOL:
91 if (reply)
switch (reply->type) {
92 case REDIS_REPLY_STATUS:
95 case REDIS_REPLY_ERROR:
99 fr_assert_msg(reply->str,
"Error response contained no error string");
119 case REDIS_REPLY_ARRAY:
120 for (i = 0; i < reply->elements; i++) {
124 if (ret < 0)
return ret;
147 switch (reply->type) {
148 case REDIS_REPLY_ERROR:
152 case REDIS_REPLY_STATUS:
156 case REDIS_REPLY_STRING:
160 case REDIS_REPLY_INTEGER:
164 case REDIS_REPLY_NIL:
168 case REDIS_REPLY_ARRAY:
170 for (i = 0; i < reply->elements; i++) {
208 bool box_error,
bool shallow)
220 switch (reply->type) {
221 case REDIS_REPLY_NIL:
230 case REDIS_REPLY_INTEGER:
231 if (reply->integer < INT32_MIN) {
234 else if (reply->integer < INT16_MIN) {
237 else if (reply->integer < INT8_MIN) {
240 else if (reply->integer < 0) {
243 else if (reply->integer > UINT32_MAX) {
246 else if (reply->integer > UINT16_MAX) {
257 #if HIREDIS_MAJOR >= 1
258 case REDIS_REPLY_DOUBLE:
263 case REDIS_REPLY_BOOL:
268 case REDIS_REPLY_ERROR:
276 #if HIREDIS_MAJOR >= 1
277 case REDIS_REPLY_BIGNUM:
279 case REDIS_REPLY_STRING:
280 case REDIS_REPLY_STATUS:
287 reply->str, reply->len,
true) < 0)
return -1;
291 #if HIREDIS_MAJOR >= 1
292 case REDIS_REPLY_VERB:
304 fr_value_box_list_insert_head(&
out->vb_group, verb);
313 fr_value_box_list_insert_head(&
out->vb_group, vtype);
319 #if HIREDIS_MAJOR >= 1
320 case REDIS_REPLY_SET:
321 case REDIS_REPLY_MAP:
322 case REDIS_REPLY_PUSH:
324 case REDIS_REPLY_ARRAY:
331 for (i = 0; i < reply->elements; i++) {
335 fr_value_box_list_talloc_free(&
out->vb_group);
338 fr_value_box_list_insert_tail(&
out->vb_group, vb);
341 FR_TYPE_VOID, NULL, box_error, shallow) < 0)
goto array_error;
366 redisReply *key, redisReply *op, redisReply *
value)
371 if (key->type != REDIS_REPLY_STRING) {
372 REDEBUG(
"Bad key type, expected string, got %s",
379 if (op->type != REDIS_REPLY_STRING) {
380 REDEBUG(
"Bad key type, expected string, got %s",
385 RDEBUG3(
"Got key : %s", key->str);
386 RDEBUG3(
"Got op : %s", op->str);
393 .prefix = TMPL_ATTR_REF_PREFIX_NO,
394 .dict_def = request->dict,
395 .list_def = request_attr_request
405 REDEBUG(
"Invalid operator \"%s\"", op->str);
409 switch (
value->type) {
410 case REDIS_REPLY_STRING:
411 case REDIS_REPLY_INTEGER:
418 RPEDEBUG(
"Failed converting Redis data");
428 REDEBUG(
"Bad value type, expected string or integer, got %s",
435 map_list_insert_tail(
out, map);
475 "bytes, got %zu bytes", (
size_t)(slen * -1));
499 out_len[2] = talloc_array_length(
new) - 1;
504 out_len[0] = key_len;
506 out_len[1] = strlen(
out[1]);
536 redisReply *
out[],
size_t out_len,
540 redisReply **out_p =
out;
542 redisReply *reply = NULL;
544 fr_assert(out_len >= (
size_t)*pipelined);
548 if ((
size_t) *pipelined > out_len) {
549 for (i = 0; i < (
size_t)*pipelined; i++) {
550 if (redisGetReply(conn->
handle, (
void **)&reply) != REDIS_OK)
break;
561 for (i = 0; i < (
size_t)*pipelined; i++) {
562 bool maybe_more =
false;
569 if (redisGetReply(conn->
handle, (
void **)&reply) == REDIS_OK) maybe_more =
true;
589 for (j = 0; j < i; j++) {
597 for (j = i + 1; j < (
size_t)*pipelined; j++) {
598 redisReply *to_clear;
600 if (redisGetReply(conn->
handle, (
void **)&to_clear) != REDIS_OK)
break;
609 return reply ? 1 : 0;
613 if (i != (
size_t)*pipelined) {
647 reply = redisCommand(conn->
handle,
"INFO SERVER");
651 if (reply->type != REDIS_REPLY_STRING) {
659 p = strstr(reply->str,
"redis_version:");
669 q = strstr(p,
"\r\n");
670 if (!q) q = p + strlen(p);
672 if ((
size_t)(q - p) >= out_len) {
692 char const *p = version;
695 num = strtoul(p, &q, 10);
701 if ((p == q) || (q[0] !=
'.')) {
708 num = strtoul(p, &q, 10);
714 if ((p == q) || (q[0] !=
'.')) {
721 num = strtoul(p, &q, 10);
722 if (num > UINT16_MAX) {
727 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_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#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.
@ TMPL_ATTR_REF_PREFIX_NO
Attribute refs have no '&' prefix.
fr_slen_t tmpl_print(fr_sbuff_t *out, tmpl_t const *vpt, tmpl_attr_prefix_t ar_prefix, fr_sbuff_escape_rules_t const *e_rules)
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
redisContext * handle
Hiredis context used when issuing commands.
#define REDIS_ERROR_TRY_AGAIN_STR
#define REDIS_ERROR_MOVED_STR
static void fr_redis_reply_free(redisReply **reply)
Wrap freeReplyObject so we consistently check for NULL pointers.
#define REDIS_ERROR_ASK_STR
#define REDIS_ERROR_NO_SCRIPT_STR
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_NO_SCRIPT
Script doesn't exist.
@ REDIS_RCODE_ASK
Attempt operation on an alternative node.
@ REDIS_RCODE_ERROR
Unrecoverable library/server error.
Connection handle, holding a redis context.
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 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.
void fr_redis_reply_print(fr_log_lvl_t lvl, redisReply *reply, request_t *request, int idx)
Print the response data in a useful treelike form.
size_t redis_reply_types_len
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_redis_rcode_t fr_redis_command_status(fr_redis_conn_t *conn, redisReply *reply)
Check the reply for errors.
fr_table_num_sorted_t const redis_reply_types[]
fr_redis_rcode_t fr_redis_pipeline_result(unsigned int *pipelined, fr_redis_rcode_t *rcode, redisReply *out[], size_t out_len, fr_redis_conn_t *conn)
Simplifies handling of pipelined commands with Redis cluster.
fr_redis_rcode_t fr_redis_get_version(char *out, size_t out_len, fr_redis_conn_t *conn)
Get the version of Redis running on the remote server.
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_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.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
#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)
Optional arguments passed to vp_tmpl functions.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
size_t strlcpy(char *dst, char const *src, size_t siz)
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.
fr_table_num_ordered_t const fr_tokens_table[]
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
char const * fr_strerror(void)
Get the last library error.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#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