27 #include <freeradius-devel/rad_assert.h>
30 {
"string", REDIS_REPLY_STRING },
31 {
"integer", REDIS_REPLY_INTEGER },
32 {
"array", REDIS_REPLY_ARRAY },
33 {
"nil", REDIS_REPLY_NIL },
34 {
"status", REDIS_REPLY_STATUS },
35 {
"error", REDIS_REPLY_ERROR },
54 static bool version_done;
59 INFO(
"libfreeradius-redis: libhiredis version: %i.%i.%i", HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH);
80 if (!reply)
switch (conn->
handle->err) {
91 case REDIS_ERR_PROTOCOL:
96 if (reply)
switch (reply->type) {
97 case REDIS_REPLY_STATUS:
100 case REDIS_REPLY_ERROR:
119 case REDIS_REPLY_ARRAY:
120 for (i = 0; i < reply->elements; i++) {
124 if (ret < 0)
return ret;
145 switch (reply->type) {
146 case REDIS_REPLY_ERROR:
147 REDEBUG(
"(%i) error : %s", idx, reply->str);
150 case REDIS_REPLY_STATUS:
151 RDEBUGX(lvl,
"(%i) status : %s", idx, reply->str);
154 case REDIS_REPLY_STRING:
155 RDEBUGX(lvl,
"(%i) string : %s", idx, reply->str);
158 case REDIS_REPLY_INTEGER:
159 RDEBUGX(lvl,
"(%i) integer : %lld", idx, reply->integer);
162 case REDIS_REPLY_NIL:
166 case REDIS_REPLY_ARRAY:
167 RDEBUGX(lvl,
"(%i) array[%zu]", idx, reply->elements);
168 for (i = 0; i < reply->elements; i++) {
203 memset(&in, 0,
sizeof(in));
205 switch (reply->type) {
206 case REDIS_REPLY_NIL:
214 case REDIS_REPLY_INTEGER:
215 if (reply->integer < INT32_MIN) {
219 if (reply->integer < 0) {
221 in.sinteger = (int32_t) reply->integer;
222 in.
length =
sizeof(in.sinteger);
224 else if (reply->integer > UINT32_MAX) {
226 in.integer64 = (uint64_t) reply->integer;
227 in.
length =
sizeof(in.integer64);
229 else if (reply->integer > UINT16_MAX) {
231 in.integer = (uint32_t) reply->integer;
232 in.
length =
sizeof(in.integer);
234 else if (reply->integer > UINT8_MAX) {
236 in.ushort = (uint16_t) reply->integer;
237 in.
length =
sizeof(in.ushort);
239 else if (reply->integer >= 0) {
241 in.byte = (uint8_t) reply->integer;
242 in.
length =
sizeof(in.byte);
248 case REDIS_REPLY_STRING:
254 case REDIS_REPLY_ARRAY:
255 case REDIS_REPLY_STATUS:
256 case REDIS_REPLY_ERROR:
260 if (src_type == dst_type) {
263 if (
value_data_cast(ctx, out, dst_type, dst_enumv, src_type, NULL, &in) < 0)
return -1;
283 redisReply *key, redisReply *op, redisReply *value)
290 if (key->type != REDIS_REPLY_STRING) {
291 REDEBUG(
"Bad key type, expected string, got %s",
292 fr_int2str(redis_reply_types, key->type,
"<UNKNOWN>"));
298 if (op->type != REDIS_REPLY_STRING) {
299 REDEBUG(
"Bad key type, expected string, got %s",
300 fr_int2str(redis_reply_types, op->type,
"<UNKNOWN>"));
304 RDEBUG3(
"Got key : %s", key->str);
305 RDEBUG3(
"Got op : %s", op->str);
310 p =
fr_asprint(NULL, value->str, value->len,
'"');
324 REDEBUG(
"Invalid operator \"%s\"", op->str);
328 switch (value->type) {
329 case REDIS_REPLY_STRING:
330 case REDIS_REPLY_INTEGER:
336 map->
lhs->tmpl_da->
type, map->
lhs->tmpl_da) < 0) {
343 map->
lhs->tmpl_da->
type, map->
lhs->tmpl_da,
true) < 0) {
350 REDEBUG(
"Bad value type, expected string or integer, got %s",
351 fr_int2str(redis_reply_types, value->type,
"<UNKNOWN>"));
395 "bytes, got %zu bytes", key_len);
401 switch (map->
rhs->tmpl_data_type) {
404 out[2] = map->
rhs->tmpl_data_value.ptr;
405 out_len[2] = map->
rhs->tmpl_data_length;
417 &map->
rhs->tmpl_data_value,
'\0');
430 out_len[0] = key_len;
432 out_len[1] = strlen(out[1]);
464 redisReply **out_p = out;
466 redisReply *reply = NULL;
471 if (pipelined > out_len) {
472 for (i = 0; i < (size_t)pipelined; i++) {
473 if (redisGetReply(conn->
handle, (
void **)&reply) != REDIS_OK)
break;
483 for (i = 0; i < (size_t)pipelined; i++) {
484 bool maybe_more =
false;
491 if (redisGetReply(conn->
handle, (
void **)&reply) == REDIS_OK) maybe_more =
true;
506 for (j = 0; j < i; j++) {
514 for (j = i + 1; j < (size_t)pipelined; j++) {
515 redisReply *to_clear;
517 if (redisGetReply(conn->
handle, (
void **)&to_clear) != REDIS_OK)
break;
522 if (rcode) *rcode = status;
523 return reply ? 1 : 0;
527 if (i != (
size_t)pipelined) {
533 if (rcode) *rcode = status;
558 reply = redisCommand(conn->
handle,
"INFO SERVER");
562 if (reply->type != REDIS_REPLY_STRING) {
564 fr_int2str(redis_reply_types, reply->type,
"<UNKNOWN>"));
570 p = strstr(reply->str,
"redis_version:");
580 q = strstr(p,
"\r\n");
581 if (!q) q = p + strlen(p);
583 if ((
size_t)(q - p) >= out_len) {
604 num = strtoul(p, &q, 10);
605 if (num > UINT8_MAX) {
610 if ((p == q) || (q[0] !=
'.')) {
617 num = strtoul(p, &q, 10);
618 if (num > UINT8_MAX) {
623 if ((p == q) || (q[0] !=
'.')) {
630 num = strtoul(p, &q, 10);
631 if (num > UINT16_MAX) {
636 if ((p == q) || (q[0] !=
'\0')) {
#define RINDENT()
Indent R* messages by one level.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
FR_NAME_NUMBER const redis_rcodes[]
int tmpl_afrom_value_data(TALLOC_CTX *ctx, vp_tmpl_t **out, value_data_t *data, PW_TYPE type, fr_dict_attr_t const *enumv, bool steal)
Create a vp_tmpl_t from a value_data_t.
vp_tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
FR_NAME_NUMBER const redis_reply_types[]
vp_tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
#define REMARKER(_m, _i, _e)
Output string with error marker, showing where format error occurred.
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
const FR_NAME_NUMBER fr_tokens_table[]
fr_connection_pool_t * pool
Pool associated with this node.
#define fr_redis_reply_free(_p)
Wrap freeReplyObject so we consistently check for NULL pointers.
void fr_redis_reply_print(log_lvl_t lvl, redisReply *reply, REQUEST *request, int idx)
Print the response data in a useful treelike form.
int fr_redis_reply_to_map(TALLOC_CTX *ctx, vp_map_t **out, REQUEST *request, redisReply *key, redisReply *op, redisReply *value)
Convert a pair of redis reply objects to a map.
#define is_truncated(_ret, _max)
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
redisContext * handle
Hiredis context used when issuing commands.
int value_data_cast(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv, PW_TYPE src_type, fr_dict_attr_t const *src_enumv, value_data_t const *src)
Convert one type of value_data_t to another.
uint32_t fr_redis_version_num(char const *version)
Convert version string into a 32bit unsigned integer for comparisons.
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
Attributes in incoming or internally proxied request.
#define REDIS_ERROR_TRY_AGAIN_STR
Unrecoverable library/server error.
fr_redis_rcode_t fr_redis_command_status(fr_redis_conn_t *conn, redisReply *reply)
Check the reply for errors.
Attempt operation on an alternative node.
#define REXDENT()
Exdent (unindent) R* messages by one level.
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.
tmpl_type_t type
What type of value tmpl refers to.
char const * fr_strerror(void)
Get the last library error.
int value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE type, const value_data_t *src)
Copy value data verbatim duplicating any buffers.
Attempt operation on an alternative node with remap.
#define REDIS_ERROR_MOVED_STR
size_t length
Length of value data.
char * talloc_bstrndup(void const *t, char const *in, size_t inlen)
Binary safe strndup function.
FR_TOKEN op
The operator that controls insertion of the dst attribute.
Transitory error, caller should retry the operation with a new connection.
int fr_redis_tuple_from_map(TALLOC_CTX *pool, char const *out[], size_t out_len[], vp_map_t *map)
Add a single map pair to an existing command string as three elements.
Common functions for interacting with Redis via hiredis.
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
size_t tmpl_snprint(char *buffer, size_t bufsize, vp_tmpl_t const *vpt, fr_dict_attr_t const *values)
Print a vp_tmpl_t to a string.
#define REDIS_ERROR_NO_SCRIPT_STR
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
fr_redis_rcode_t fr_redis_pipeline_result(fr_redis_rcode_t *rcode, redisReply *out[], size_t out_len, fr_redis_conn_t *conn, int pipelined)
Simplifies handling of pipelined commands with Redis cluster.
fr_redis_rcode_t
Codes are ordered inversely by priority.
size_t strlcpy(char *dst, char const *src, size_t siz)
int fr_redis_reply_to_value_data(TALLOC_CTX *ctx, value_data_t *out, redisReply *reply, PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv)
Convert a string or integer type to value_data_t of specified type.
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
#define REDIS_ERROR_ASK_STR
String of printable characters.
Operation was successfull.
#define RDEBUGX(_l, fmt,...)
Connection handle, holding a redis context.
PW_TYPE
Internal data types used within libfreeradius.
size_t value_data_snprint(char *out, size_t outlen, PW_TYPE type, fr_dict_attr_t const *enumv, value_data_t const *data, char quote)
Print the value of an attribute to a string.