The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
redis.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: 4fdca8dc62bd55b83baa02a4f9e462587c2be228 $
19 * @file redis.c
20 * @brief Common functions for interacting with Redis via hiredis
21 *
22 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 * @copyright 2000,2006,2015 The FreeRADIUS server project
24 * @copyright 2011 TekSavvy Solutions (gabe@teksavvy.com)
25 */
26#include <freeradius-devel/redis/base.h>
27#include <freeradius-devel/util/debug.h>
28#include <freeradius-devel/util/value.h>
29#include "attrs.h"
30
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 }
38};
40
42 { L("ask"), REDIS_RCODE_ASK },
43 { L("error"), REDIS_RCODE_ERROR },
44 { L("move"), REDIS_RCODE_MOVE },
45 { L("reconnect"), REDIS_RCODE_RECONNECT },
46 { L("success"), REDIS_RCODE_SUCCESS },
47 { L("try again"), REDIS_RCODE_TRY_AGAIN }
48};
50
52
55 { .out = &dict_redis, .proto = "redis" },
57};
58
78
81 { .out = &attr_redis_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_redis },
82 { .out = &attr_redis_log_prefix, .name = "Log-Prefix", .type = FR_TYPE_STRING, .dict = &dict_redis },
83 { .out = &attr_redis_max_nodes, .name = "Max-Nodes", .type = FR_TYPE_UINT8, .dict = &dict_redis },
84 { .out = &attr_redis_bootstrap_node, .name = "Bootstrap-Node", .type = FR_TYPE_STRING, .dict = &dict_redis },
85 { .out = &attr_redis_bootstrap_port, .name = "Bootstrap-Port", .type = FR_TYPE_UINT16, .dict = &dict_redis },
86 { .out = &attr_redis_username, .name = "Username", .type = FR_TYPE_STRING, .dict = &dict_redis },
87 { .out = &attr_redis_password, .name = "Password", .type = FR_TYPE_STRING, .dict = &dict_redis },
88 { .out = &attr_redis_cluster_id, .name = "Cluster-Id", .type = FR_TYPE_UINT16, .dict = &dict_redis },
89 { .out = &attr_redis_shard, .name = "Shard", .type = FR_TYPE_TLV, .dict = &dict_redis },
90 { .out = &attr_redis_slot, .name = "Shard.Slot", .type = FR_TYPE_TLV, .dict = &dict_redis },
91 { .out = &attr_redis_slot_start, .name = "Shard.Slot.Start", .type = FR_TYPE_UINT16, .dict = &dict_redis },
92 { .out = &attr_redis_slot_end, .name = "Shard.Slot.End", .type = FR_TYPE_UINT16, .dict = &dict_redis },
93 { .out = &attr_redis_node, .name = "Shard.Node", .type = FR_TYPE_TLV, .dict = &dict_redis },
94 { .out = &attr_redis_node_endpoint, .name = "Shard.Node.Endpoint", .type = FR_TYPE_STRING, .dict = &dict_redis },
95 { .out = &attr_redis_node_port, .name = "Shard.Node.Port", .type = FR_TYPE_UINT16, .dict = &dict_redis },
96 { .out = &attr_redis_node_role, .name = "Shard.Node.Role", .type = FR_TYPE_UINT8, .dict = &dict_redis },
97 { .out = &attr_redis_force_update, .name = "Force-Update", .type = FR_TYPE_BOOL, .dict = &dict_redis },
98 { .out = &attr_redis_use_tls, .name = "Use-TLS", .type = FR_TYPE_BOOL, .dict = &dict_redis },
99 { .out = &attr_redis_tls_conf, .name = "TLS-Conf", .type = FR_TYPE_UINT64, .dict = &dict_redis },
100
102};
103
104/** Print the version of libhiredis the server was built against
105 *
106 */
108{
109 INFO("libfreeradius-redis: libhiredis version: %i.%i.%i", HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH);
110}
111
112static int _redis_dict_init(UNUSED void *uctx)
113{
115 PERROR("%s", __FUNCTION__);
116 return -1;
117 }
119 PERROR("%s", __FUNCTION__);
121 return -1;
122 }
123
124 return 0;
125}
126
127static int _redis_dict_free(UNUSED void *uctx)
128{
130 return 0;
131}
132
133/** Load the Redis dictionaries
134 *
135 */
137{
138 int ret;
139
140 fr_atexit_global_once_ret(&ret, _redis_dict_init, _redis_dict_free, NULL);
141
142 return ret;
143}
144
145/** Print the response data in a useful treelike form
146 *
147 * @param[in] lvl to print data at.
148 * @param[in] reply to print.
149 * @param[in] request The current request.
150 * @param[in] idx Response number.
151 * @param[in] status code from processing last reply.
152 */
153void fr_redis_reply_print(fr_log_lvl_t lvl, redisReply *reply, request_t *request, int idx, fr_redis_rcode_t status)
154{
155 size_t i = 0;
156
157 if (!reply) return;
158
159 switch (reply->type) {
160 case REDIS_REPLY_ERROR:
161 if (status == REDIS_RCODE_MOVE) {
162 ROPTIONAL(RWARN, WARN, "(%i) warn : %s", idx, reply->str);
163 } else {
164 ROPTIONAL(REDEBUG, ERROR, "(%i) error : %s", idx, reply->str);
165 }
166 break;
167
168 case REDIS_REPLY_STATUS:
169 ROPTIONAL(RDEBUGX, DEBUGX, lvl, "(%i) status : %s", idx, reply->str);
170 break;
171
172 case REDIS_REPLY_STRING:
173 ROPTIONAL(RDEBUGX, DEBUGX, lvl, "(%i) string : %s", idx, reply->str);
174 break;
175
176 case REDIS_REPLY_INTEGER:
177 ROPTIONAL(RDEBUGX, DEBUGX, lvl, "(%i) integer : %lld", idx, reply->integer);
178 break;
179
180 case REDIS_REPLY_NIL:
181 ROPTIONAL(RDEBUGX, DEBUGX, lvl, "(%i) nil", idx);
182 break;
183
184 case REDIS_REPLY_ARRAY:
185 ROPTIONAL(RDEBUGX, DEBUGX, lvl, "(%i) array[%zu]", idx, reply->elements);
186 for (i = 0; i < reply->elements; i++) {
187 if (request) RINDENT();
188 fr_redis_reply_print(lvl, reply->element[i], request, i, status);
189 if (request) REXDENT();
190 }
191 break;
192 }
193}
194
195/** Convert a string or integer type to #fr_value_box_t of specified type
196 *
197 * Will work with REDIS_REPLY_STRING (which is converted to #FR_TYPE_STRING
198 * then cast to dst_type), or REDIS_REPLY_INTEGER (which is converted to
199 * #FR_TYPE_UINT64, then cast to dst_type).
200 *
201 * @note Any unsupported types will trigger an assert. You must check the
202 * reply type prior to calling this function.
203 *
204 * @param[in,out] ctx to allocate any buffers in.
205 * @param[out] out Where to write the cast type.
206 * @param[in] reply to process.
207 * @param[in] dst_type to convert to. May be FR_TYPE_VOID
208 * to infer type.
209 * @param[in] dst_enumv Used to convert string types to
210 * integers for attribute with enumerated
211 * values.
212 * @param[in] box_error If true then REDIS_REPLY_ERROR will be
213 * copied to a box, otherwise we'll return
214 * and error with the contents of the error
215 * available on the thread local error stack.
216 * @param[in] shallow If true, we shallow copy strings.
217 * @return
218 * - 1 if we received a NIL reply.
219 * - 0 on success.
220 * - -1 on cast or parse failure.
221 */
222int fr_redis_reply_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, redisReply *reply,
223 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
224 bool box_error, bool shallow)
225{
227 fr_value_box_t *to_cast;
228
229 if (dst_type != FR_TYPE_VOID) {
231 to_cast = &in;
232 } else {
233 to_cast = out;
234 }
235
236 switch (reply->type) {
237 case REDIS_REPLY_NIL:
238 fr_value_box_init(out, FR_TYPE_NULL, NULL, false);
239 return 1;
240
241 /*
242 * Try and convert the integer to the smallest
243 * and simplest type possible, to give the cast
244 * the greatest chance of success.
245 */
246 case REDIS_REPLY_INTEGER:
247 if (reply->integer < INT32_MIN) { /* 64bit signed */
248 fr_value_box(to_cast, (int64_t) reply->integer, true);
249 }
250 else if (reply->integer < INT16_MIN) { /* 32bit signed */
251 fr_value_box(to_cast, (int32_t) reply->integer, true);
252 }
253 else if (reply->integer < INT8_MIN) { /* 16bit signed */
254 fr_value_box(to_cast, (int16_t) reply->integer, true);
255 }
256 else if (reply->integer < 0) { /* 8bit signed */
257 fr_value_box(to_cast, (int8_t) reply->integer, true);
258 }
259 else if (reply->integer > UINT32_MAX) { /* 64bit unsigned */
260 fr_value_box(to_cast, (uint64_t) reply->integer, true);
261 }
262 else if (reply->integer > UINT16_MAX) { /* 32bit unsigned */
263 fr_value_box(to_cast, (uint32_t) reply->integer, true);
264 }
265 else if (reply->integer > UINT8_MAX) { /* 16bit unsigned */
266 fr_value_box(to_cast, (uint16_t) reply->integer, true);
267 }
268 else { /* 8bit unsigned */
269 fr_value_box(to_cast, (uint8_t) reply->integer, true);
270 }
271 break;
272
273#if HIREDIS_MAJOR >= 1
274 case REDIS_REPLY_DOUBLE:
275 /* reply->str is \0 terminated in this case */
276 fr_value_box(to_cast, strtod(reply->str, NULL), true);
277 break;
278
279 case REDIS_REPLY_BOOL:
280 fr_value_box(to_cast, (bool)reply->integer, true);
281 break;
282#endif
283
284 case REDIS_REPLY_ERROR:
285 if (!box_error) {
286 fr_strerror_printf("Redis error: %pV",
287 fr_box_strvalue_len(reply->str, reply->len));
288 return -1;
289 }
291
292#if HIREDIS_MAJOR >= 1
293 case REDIS_REPLY_BIGNUM: /* FIXME - Could try and convert to integer ? */
294#endif
295 case REDIS_REPLY_STRING:
296 case REDIS_REPLY_STATUS:
297 fr_value_box_init(out, FR_TYPE_STRING, NULL, false);
298
299 if (shallow) {
300 fr_value_box_bstrndup_shallow(to_cast, NULL, reply->str, reply->len, true);
301 } else {
302 if (fr_value_box_bstrndup(to_cast->talloced ? to_cast : ctx, to_cast, NULL,
303 reply->str, reply->len, true) < 0) return -1;
304 }
305 break;
306
307#if HIREDIS_MAJOR >= 1
308 case REDIS_REPLY_VERB:
309 {
310 fr_value_box_t *verb, *vtype;
311
312 fr_value_box_init(out, FR_TYPE_GROUP, NULL, true);
313
314 verb = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL);
315 if (unlikely(!verb)) {
316 fr_strerror_const("Out of memory");
317 return -1;
318 }
319 if (fr_value_box_bstrndup(verb, verb, NULL, reply->str, reply->len, true) < 0) return -1;
320 fr_value_box_list_insert_head(&out->vb_group, verb);
321
322 vtype = fr_value_box_alloc(ctx, FR_TYPE_STRING, NULL);
323 if (unlikely(!vtype)) {
324 fr_strerror_const("Out of memory");
325 talloc_free(verb);
326 return -1;
327 }
328 if (fr_value_box_strdup(ctx, vtype, NULL, reply->vtype, true) < 0) return -1;
329 fr_value_box_list_insert_head(&out->vb_group, vtype);
330
331 }
332 break;
333#endif
334
335#if HIREDIS_MAJOR >= 1
336 case REDIS_REPLY_SET:
337 case REDIS_REPLY_MAP:
338 case REDIS_REPLY_PUSH:
339#endif
340 case REDIS_REPLY_ARRAY:
341 {
342 fr_value_box_t *vb;
343 size_t i;
344
345 fr_value_box_init(out, FR_TYPE_GROUP, NULL, true);
346
347 for (i = 0; i < reply->elements; i++) {
348 vb = fr_value_box_alloc_null(ctx);
349 if (unlikely(!vb)) {
350 array_error:
351 fr_value_box_list_talloc_free(&out->vb_group);
352 return -1;
353 }
354
355 if (fr_redis_reply_to_value_box(vb, vb, reply->element[i],
356 FR_TYPE_VOID, NULL, box_error, shallow) < 0) goto array_error;
357 fr_value_box_list_insert_tail(&out->vb_group, vb);
358 }
359 }
360 }
361
362 if ((dst_type != FR_TYPE_VOID) && (fr_value_box_cast(ctx, out, dst_type, dst_enumv, to_cast) < 0)) return -1;
363
364 return 0;
365}
366
367/** Convert a pair of redis reply objects to a map
368 *
369 * The maps can then be applied using #map_to_request.
370 *
371 * @param[in,out] ctx to allocate maps in.
372 * @param[out] out Where to write the head of the new maps list.
373 * @param[in] request The current request.
374 * @param[in] key to process.
375 * @param[in] op to process.
376 * @param[in] value to process.
377 * @return
378 * - 0 on success.
379 * - -1 on failure.
380 */
381int fr_redis_reply_to_map(TALLOC_CTX *ctx, map_list_t *out, request_t *request,
382 redisReply *key, redisReply *op, redisReply *value)
383{
384 map_t *map = NULL;
385 ssize_t slen;
386
387 if (key->type != REDIS_REPLY_STRING) {
388 REDEBUG("Bad key type, expected string, got %s",
389 fr_table_str_by_value(redis_reply_types, key->type, "<UNKNOWN>"));
390 error:
391 TALLOC_FREE(map);
392 return -1;
393 }
394
395 if (op->type != REDIS_REPLY_STRING) {
396 REDEBUG("Bad op type, expected string, got %s",
397 fr_table_str_by_value(redis_reply_types, op->type, "<UNKNOWN>"));
398 goto error;
399 }
400
401 RDEBUG3("Got key : %s", key->str);
402 RDEBUG3("Got op : %s", op->str);
403 RDEBUG3("Got value : %pV", fr_box_strvalue_len(value->str, value->len));
404
405 MEM(map = talloc_zero(ctx, map_t));
406 slen = tmpl_afrom_attr_str(map, NULL, &map->lhs, key->str,
407 &(tmpl_rules_t){
408 .attr = {
409 .dict_def = request->local_dict,
410 .list_def = request_attr_request
411 }
412 });
413 if (slen <= 0) {
414 REMARKER(key->str, -slen, "%s", fr_strerror());
415 goto error;
416 }
417
419 if (map->op == T_INVALID) {
420 REDEBUG("Invalid operator \"%s\"", op->str);
421 goto error;
422 }
423
424 switch (value->type) {
425 case REDIS_REPLY_STRING:
426 case REDIS_REPLY_INTEGER:
427 {
429
430 /* Logs own errors */
432 tmpl_attr_tail_da(map->lhs)->type, tmpl_attr_tail_da(map->lhs), false, false) < 0) {
433 RPEDEBUG("Failed converting Redis data");
434 goto error;
435 }
436
437 /* This will only fail only memory allocation errors */
438 if (tmpl_afrom_value_box(map, &map->rhs, &vb, true) < 0) goto error;
439 }
440 break;
441
442 default:
443 REDEBUG("Bad value type, expected string or integer, got %s",
444 fr_table_str_by_value(redis_reply_types, value->type, "<UNKNOWN>"));
445 goto error;
446
447 }
448 MAP_VERIFY(map);
449
450 map_list_insert_tail(out, map);
451
452 return 0;
453}
454
455/** Add a single map pair to an existing command string as three elements
456 *
457 * - Integer types will be encoded as integers.
458 * - Strings and octets will be encoded in their raw form.
459 * - Other types will be converted to their printable form and will be encoded as strings.
460 *
461 * @note lhs must be a #TMPL_TYPE_ATTR.
462 * @note rhs must be a #TMPL_TYPE_DATA.
463 *
464 * @param pool to allocate any buffers in.
465 * @param out Where to write pointers to the member of the tuple. Unused elements should be
466 * a multiple of three, and it should have at least three unused elements.
467 * @param out_len Where to write the size of the data pointed to by the equivalent index
468 * in the out array.
469 * @param map to convert.
470 * @return
471 * 0 on success.
472 * -1 on failure.
473 */
474int fr_redis_tuple_from_map(TALLOC_CTX *pool, char const *out[], size_t out_len[], map_t *map)
475{
476 char *new;
477
478 char key_buf[256];
479 fr_sbuff_t key_buf_sbuff = FR_SBUFF_OUT(key_buf, sizeof(key_buf));
480 char *key;
481 size_t key_len;
482 ssize_t slen;
483
486
487 slen = tmpl_print(&key_buf_sbuff, map->lhs, NULL);
488 if (slen < 0) {
489 fr_strerror_printf("Key too long. Must be < " STRINGIFY(sizeof(key_buf)) " "
490 "bytes, got %zu bytes", (size_t)(slen * -1));
491 return -1;
492 }
493 key_len = (size_t)slen;
494 key = talloc_bstrndup(pool, fr_sbuff_start(&key_buf_sbuff), key_len);
495 if (!key) return -1;
496
497 switch (tmpl_value_type(map->rhs)) {
498 case FR_TYPE_STRING:
499 case FR_TYPE_OCTETS:
500 out[2] = tmpl_value(map->rhs)->datum.ptr;
501 out_len[2] = tmpl_value_length(map->rhs);
502 break;
503
504 /*
505 * For everything else we get the string representation
506 */
507 default:
508 fr_value_box_aprint(pool, &new, tmpl_value(map->rhs), NULL);
509 if (!new) {
510 talloc_free(key);
511 return -1;
512 }
513 out[2] = new;
514 out_len[2] = talloc_strlen(new);
515 break;
516 }
517
518 out[0] = key;
519 out_len[0] = key_len;
521 out_len[1] = strlen(out[1]);
522
523 return 0;
524}
525
526/** Parse the reply from the Redis command INFO SERVER to extract the version
527 *
528 * @param[out] out Where to write the version string.
529 * @param[in] out_len Length of the version string buffer.
530 * @param[in] reply Redis reply to parse
531 * @return
532 * - 0 on success.
533 * - -1 on command/response mismatch or command error.
534 */
535int fr_redis_parse_version(char *out, size_t out_len, redisReply *reply)
536{
537 fr_sbuff_t sbuff;
538
539 if (reply->type != REDIS_REPLY_STRING) {
540 fr_strerror_printf("Bad value type, expected string or integer, got %s",
541 fr_table_str_by_value(redis_reply_types, reply->type, "<UNKNOWN>"));
542 error:
543 return -1;
544 }
545
546 fr_sbuff_init_in(&sbuff, reply->str, reply->len);
547
548 if (!fr_sbuff_adv_to_str_literal(&sbuff, SIZE_MAX, "redis_version:")) {
549 fr_strerror_const("Response did not contain version string");
550 goto error;
551 }
552 fr_sbuff_advance(&sbuff, sizeof("redis_version:") -1);
553
554 if (fr_sbuff_out_bstrncpy_until(&FR_SBUFF_OUT(out, out_len), &sbuff, SIZE_MAX, &FR_SBUFF_TERMS(L("\r\n")), NULL) == 0) {
555 fr_strerror_printf("Failed extracting version string");
556 goto error;
557 }
558
559 return 0;
560}
561
562/** Convert version string into a 32bit unsigned integer for comparisons
563 *
564 * @param[in] version string to parse.
565 * @return 32bit unsigned integer representing the version string.
566 */
567uint32_t fr_redis_version_num(char const *version)
568{
569 unsigned long num;
570 uint32_t ret;
571 char const *p = version;
572 char *q;
573
574 num = strtoul(p, &q, 10);
575 if (num > UINT8_MAX) {
576 fr_strerror_printf("Major version number %lu greater than " STRINGIFY(UINT8_MAX), num);
577 return 0;
578 }
579
580 if ((p == q) || (q[0] != '.')) {
581 fr_strerror_printf("Trailing garbage in Redis version \"%s\"", q);
582 return 0;
583 }
584 ret = num << 24;
585 p = q + 1;
586
587 num = strtoul(p, &q, 10);
588 if (num > UINT8_MAX) {
589 fr_strerror_printf("Minor version number %lu greater than " STRINGIFY(UINT8_MAX), num);
590 return 0;
591 }
592
593 if ((p == q) || (q[0] != '.')) {
594 fr_strerror_printf("Trailing garbage in Redis version \"%s\"", q);
595 return 0;
596 }
597 ret |= num << 16;
598 p = q + 1;
599
600 num = strtoul(p, &q, 10);
601 if (num > UINT16_MAX) {
602 fr_strerror_printf("Minor version number %lu greater than " STRINGIFY(UINT16_MAX), num);
603 return 0;
604 }
605
606 if ((p == q) || (q[0] != '\0')) {
607 fr_strerror_printf("Trailing garbage in Redis version \"%s\"", q);
608 return 0;
609 }
610
611 return ret | num;
612}
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:228
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:391
#define STRINGIFY(x)
Definition build.h:216
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
#define NUM_ELEMENTS(_t)
Definition build.h:406
#define MEM(x)
Definition debug.h:38
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define fr_dict_autofree(_to_free)
Definition dict.h:915
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
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.
Definition dict_util.c:4393
#define fr_dict_autoload(_to_load)
Definition dict.h:912
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
static fr_slen_t in
Definition dict.h:882
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
Test enumeration values.
Definition dict_test.h:92
talloc_free(hp)
#define PERROR(_fmt,...)
Definition log.h:233
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:460
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition log.h:545
#define RDEBUG3(fmt,...)
Definition log.h:360
#define RWARN(fmt,...)
Definition log.h:314
#define RDEBUGX(_l, fmt,...)
Definition log.h:357
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition log.h:515
#define RPEDEBUG(fmt,...)
Definition log.h:393
#define DEBUGX(_lvl, _fmt,...)
Definition log.h:273
#define RINDENT()
Indent R* messages by one level.
Definition log.h:447
fr_log_lvl_t
Definition log.h:64
unsigned short uint16_t
fr_type_t
@ 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_VOID
User data.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
long int ssize_t
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)
unsigned char uint8_t
fr_slen_t tmpl_print(fr_sbuff_t *out, tmpl_t const *vpt, fr_sbuff_escape_rules_t const *e_rules)
unsigned long int size_t
#define UINT8_MAX
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define WARN(fmt,...)
#define INFO(fmt,...)
Definition radict.c:63
fr_redis_rcode_t
Codes are ordered inversely by priority.
Definition base.h:69
@ REDIS_RCODE_RECONNECT
Transitory error, caller should retry the operation with a new connection.
Definition base.h:73
@ REDIS_RCODE_SUCCESS
Operation was successful.
Definition base.h:70
@ REDIS_RCODE_MOVE
Attempt operation on an alternative node with remap.
Definition base.h:76
@ REDIS_RCODE_TRY_AGAIN
Try the operation again.
Definition base.h:72
@ REDIS_RCODE_ASK
Attempt operation on an alternative node.
Definition base.h:75
@ REDIS_RCODE_ERROR
Unrecoverable library/server error.
Definition base.h:71
fr_dict_attr_t const * attr_redis_node_role
Definition redis.c:74
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.
Definition redis.c:153
fr_dict_autoload_t redis_base_dict[]
Definition redis.c:54
static int _redis_dict_free(UNUSED void *uctx)
Definition redis.c:127
fr_table_num_sorted_t const redis_rcodes[]
Definition redis.c:41
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.
Definition redis.c:222
int redis_dict_init(void)
Load the Redis dictionaries.
Definition redis.c:136
fr_dict_attr_t const * attr_redis_bootstrap_node
Definition redis.c:62
fr_dict_attr_t const * attr_redis_use_tls
Definition redis.c:76
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.
Definition redis.c:474
fr_dict_attr_t const * attr_redis_slot_end
Definition redis.c:70
fr_dict_attr_t const * attr_redis_force_update
Definition redis.c:75
size_t redis_reply_types_len
Definition redis.c:39
fr_dict_attr_t const * attr_redis_packet_type
Definition redis.c:59
fr_dict_attr_t const * attr_redis_log_prefix
Definition redis.c:60
fr_dict_attr_t const * attr_redis_node
Definition redis.c:71
fr_dict_attr_t const * attr_redis_node_port
Definition redis.c:73
fr_dict_attr_t const * attr_redis_slot
Definition redis.c:68
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
Definition redis.c:107
uint32_t fr_redis_version_num(char const *version)
Convert version string into a 32bit unsigned integer for comparisons.
Definition redis.c:567
fr_dict_t const * dict_redis
Definition redis.c:51
fr_table_num_sorted_t const redis_reply_types[]
Definition redis.c:31
size_t redis_rcodes_len
Definition redis.c:49
fr_dict_attr_t const * attr_redis_slot_start
Definition redis.c:69
fr_dict_attr_t const * attr_redis_max_nodes
Definition redis.c:61
fr_dict_attr_autoload_t redis_base_dict_attr[]
Definition redis.c:80
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.
Definition redis.c:535
fr_dict_attr_t const * attr_redis_password
Definition redis.c:65
fr_dict_attr_t const * attr_redis_bootstrap_port
Definition redis.c:63
fr_dict_attr_t const * attr_redis_cluster_id
Definition redis.c:66
fr_dict_attr_t const * attr_redis_tls_conf
Definition redis.c:77
fr_dict_attr_t const * attr_redis_username
Definition redis.c:64
fr_dict_attr_t const * attr_redis_node_endpoint
Definition redis.c:72
static int _redis_dict_init(UNUSED void *uctx)
Definition redis.c:112
fr_dict_attr_t const * attr_redis_shard
Definition redis.c:67
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.
Definition redis.c:381
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition sbuff.h:190
#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 MAP_VERIFY(_x)
Definition map.h:108
#define tmpl_value_length(_tmpl)
Definition tmpl.h:938
#define tmpl_value(_tmpl)
Definition tmpl.h:937
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)
Definition tmpl.h:208
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)
Definition tmpl.h:206
#define tmpl_value_type(_tmpl)
Definition tmpl.h:939
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:801
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:336
Value pair map.
Definition map.h:77
fr_token_t op
The operator that controls insertion of the dst attribute.
Definition map.h:82
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Definition map.h:78
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Definition map.h:79
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:685
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
Definition talloc.c:618
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
Definition talloc.h:143
fr_table_num_ordered_t const fr_tokens_table[]
Definition token.c:33
@ T_INVALID
Definition token.h:37
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
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.
Definition value.c:3968
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.
Definition value.c:4643
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.
Definition value.c:4862
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.
Definition value.c:4949
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:644
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.
Definition value.h:511
#define fr_box_strvalue_len(_val, _len)
Definition value.h:309
#define fr_value_box_init_null(_vb)
Initialise an empty/null box that will be filled later.
Definition value.h:616
#define fr_value_box(_box, _var, _tainted)
Automagically fill in a box, determining the value type from the type of the C variable.
Definition value.h:904
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition value.h:655
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:610
static size_t char ** out
Definition value.h:1030