The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
base.h
Go to the documentation of this file.
1#pragma once
2/*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or (at
6 * your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18/**
19 * $Id: ea3061098c4704c6f1e9f8770e24fd5309b719ce $
20 * @file lib/redis/base.h
21 * @brief Common functions for interacting with Redis via hiredis
22 *
23 * @author Arran Cudbard-Bell
24 *
25 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
26 * @copyright 2000,2006,2015 The FreeRADIUS server project
27 * @copyright 2011 TekSavvy Solutions (gabe@teksavvy.com)
28 */
29RCSIDH(redis_h, "$Id: ea3061098c4704c6f1e9f8770e24fd5309b719ce $")
30
31#include <freeradius-devel/server/base.h>
32#include <freeradius-devel/server/map.h>
33#include <freeradius-devel/server/module.h>
34
35//DIAG_OFF(extra-semi-stmt)
36#include <hiredis/hiredis.h>
37//DIAG_ON(extra-semi-stmt)
38
39#ifdef __cplusplus
40extern "C" {
41#endif
42
43#define MAX_REDIS_COMMAND_LEN 4096
44#define MAX_REDIS_ARGS 256
45
46#define REDIS_ERROR_MOVED_STR "MOVED"
47#define REDIS_ERROR_ASK_STR "ASK"
48#define REDIS_ERROR_TRY_AGAIN_STR "TRYAGAIN"
49#define REDIS_ERROR_NO_SCRIPT_STR "NOSCRIPT"
50#define REDIS_DEFAULT_PORT 6379
51
53
54/** Wrap freeReplyObject so we consistently check for NULL pointers
55 *
56 * Older versions such as 0.10 (which ship with Ubuntu <= 14.10)
57 * don't check for NULL pointer before attempting to free, so we
58 * get a NULL pointer dereference in some cases.
59 *
60 * Rather than go back through the many calls to freeReplyObject
61 * and attempt to determine code paths that may result in it being
62 * called on a NULL pointer, we use this to always check.
63 */
64static inline void fr_redis_reply_free(redisReply **reply)
65{
66 if (*reply) freeReplyObject(*reply);
67 *reply = NULL;
68}
69
70static inline void fr_redis_pipeline_free(redisReply *reply[], size_t num)
71{
72 size_t i;
73 for (i = 0; i < num; i++) fr_redis_reply_free(&(reply[i]));
74}
75
77extern size_t redis_reply_types_len;
79extern size_t redis_rcodes_len;
80
81/** Codes are ordered inversely by priority
82 *
83 * To simplify handling the return codes from pipelined commands,
84 * the lowest status code, and the reply which accompanies it should
85 * be returned to the redis cluster code.
86 */
87typedef enum {
88 REDIS_RCODE_SUCCESS = 0, //!< Operation was successful.
89 REDIS_RCODE_ERROR = -1, //!< Unrecoverable library/server error.
90 REDIS_RCODE_TRY_AGAIN = -2, //!< Try the operation again.
91 REDIS_RCODE_RECONNECT = -3, //!< Transitory error, caller should retry the operation
92 //!< with a new connection.
93 REDIS_RCODE_ASK = -4, //!< Attempt operation on an alternative node.
94 REDIS_RCODE_MOVE = -5, //!< Attempt operation on an alternative node with remap.
95 REDIS_RCODE_NO_SCRIPT = -6, //!< Script doesn't exist.
97
98/** Connection handle, holding a redis context
99 */
100typedef struct {
101 redisContext *handle; //!< Hiredis context used when issuing commands.
102 fr_redis_cluster_node_t *node; //!< Node this connection is to.
104
105/** Configuration parameters for a redis connection
106 *
107 * @note should be passed as instance data to #module_rlm_connection_pool_init.
108 */
109typedef struct {
110 char const **hostname; //!< of Redis server.
111 uint16_t port; //!< of Redis daemon.
112 uint32_t database; //!< number on Redis server.
113 bool use_tls; //!< use TLS.
114 bool use_cluster_map;//!< use cluster map.
115
116 char const *username; //!< for acls.
117 char const *password; //!< to authenticate to Redis.
118
119 uint8_t max_nodes; //!< Maximum number of cluster nodes to connect to.
120 uint32_t max_redirects; //!< Maximum number of times we can be redirected.
121 uint32_t max_retries; //!< Maximum number of times we attempt a command
122 //!< when receiving successive -TRYAGAIN messages.
123 uint32_t max_alt; //!< Maximum alternative nodes to try.
124 fr_time_delta_t retry_delay; //!< How long to wait when we received a -TRYAGAIN
125 //!< message.
127
129
130 char const *log_prefix;
132
133#define REDIS_COMMON_CONFIG \
134 { FR_CONF_OFFSET_FLAGS("server", CONF_FLAG_REQUIRED | CONF_FLAG_MULTI, fr_redis_conf_t, hostname) }, \
135 { FR_CONF_OFFSET("port", fr_redis_conf_t, port), .dflt = "6379" }, \
136 { FR_CONF_OFFSET("database", fr_redis_conf_t, database), .dflt = "0" }, \
137 { FR_CONF_OFFSET("use_tls", fr_redis_conf_t, use_tls), .dflt = "no" }, \
138 { FR_CONF_OFFSET("use_cluster_map", fr_redis_conf_t, use_cluster_map), .dflt = "yes" }, \
139 { FR_CONF_OFFSET("username", fr_redis_conf_t, username) }, \
140 { FR_CONF_OFFSET_FLAGS("password", CONF_FLAG_SECRET, fr_redis_conf_t, password) }, \
141 { FR_CONF_OFFSET("max_nodes", fr_redis_conf_t, max_nodes), .dflt = "20" }, \
142 { FR_CONF_OFFSET("max_alt", fr_redis_conf_t, max_alt), .dflt = "3" }, \
143 { FR_CONF_OFFSET("max_redirects", fr_redis_conf_t, max_redirects), .dflt = "2" }
144
145void fr_redis_version_print(void);
146
147/*
148 * Command and resulting parsing
149 */
151
152void fr_redis_reply_print(fr_log_lvl_t lvl, redisReply *reply, request_t *request, int idx);
153
154int fr_redis_reply_to_value_box(TALLOC_CTX *ctx, fr_value_box_t *out, redisReply *reply,
155 fr_type_t dst_type, fr_dict_attr_t const *dst_enumv,
156 bool box_error, bool shallow) CC_HINT(nonnull(2,3));
157
158int fr_redis_reply_to_map(TALLOC_CTX *ctx, map_list_t *out,
159 request_t *request, redisReply *key, redisReply *op, redisReply *value);
160
161int fr_redis_tuple_from_map(TALLOC_CTX *pool, char const *out[], size_t out_len[], map_t *map);
162
163fr_redis_rcode_t fr_redis_get_version(char *out, size_t out_len, fr_redis_conn_t *conn);
164
165uint32_t fr_redis_version_num(char const *version);
166
167/*
168 * Process response from pipelined command.
169 */
170fr_redis_rcode_t fr_redis_pipeline_result(unsigned int *pipelined, fr_redis_rcode_t *rcode,
171 redisReply *out[], size_t out_len,
172 fr_redis_conn_t *conn) CC_HINT(nonnull);
173
174#ifdef __cplusplus
175}
176#endif
#define RCSIDH(h, id)
Definition build.h:484
A Redis cluster node.
Definition cluster.c:213
Test enumeration values.
Definition dict_test.h:92
fr_log_lvl_t
Definition log.h:67
unsigned short uint16_t
fr_type_t
unsigned int uint32_t
unsigned char uint8_t
static void fr_redis_pipeline_free(redisReply *reply[], size_t num)
Definition base.h:70
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:206
uint8_t max_nodes
Maximum number of cluster nodes to connect to.
Definition base.h:119
fr_time_delta_t reconnection_delay
Definition base.h:128
fr_table_num_sorted_t const redis_rcodes[]
Definition redis.c:40
bool use_cluster_map
use cluster map.
Definition base.h:114
redisContext * handle
Hiredis context used when issuing commands.
Definition base.h:101
char const * username
for acls.
Definition base.h:116
uint32_t database
number on Redis server.
Definition base.h:112
fr_time_delta_t connection_timeout
Definition base.h:126
bool use_tls
use TLS.
Definition base.h:113
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:459
fr_redis_cluster_node_t * node
Node this connection is to.
Definition base.h:102
uint16_t port
of Redis daemon.
Definition base.h:111
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.
Definition redis.c:141
size_t redis_reply_types_len
Definition redis.c:38
static void fr_redis_reply_free(redisReply **reply)
Wrap freeReplyObject so we consistently check for NULL pointers.
Definition base.h:64
uint32_t max_redirects
Maximum number of times we can be redirected.
Definition base.h:120
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
Definition redis.c:53
uint32_t fr_redis_version_num(char const *version)
Convert version string into a 32bit unsigned integer for comparisons.
Definition redis.c:688
fr_redis_rcode_t fr_redis_command_status(fr_redis_conn_t *conn, redisReply *reply)
Check the reply for errors.
Definition redis.c:71
fr_table_num_sorted_t const redis_reply_types[]
Definition redis.c:30
size_t redis_rcodes_len
Definition redis.c:48
fr_time_delta_t retry_delay
How long to wait when we received a -TRYAGAIN message.
Definition base.h:124
char const * log_prefix
Definition base.h:130
char const ** hostname
of Redis server.
Definition base.h:110
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.
Definition redis.c:535
fr_redis_rcode_t
Codes are ordered inversely by priority.
Definition base.h:87
@ REDIS_RCODE_RECONNECT
Transitory error, caller should retry the operation with a new connection.
Definition base.h:91
@ REDIS_RCODE_SUCCESS
Operation was successful.
Definition base.h:88
@ REDIS_RCODE_MOVE
Attempt operation on an alternative node with remap.
Definition base.h:94
@ REDIS_RCODE_TRY_AGAIN
Try the operation again.
Definition base.h:90
@ REDIS_RCODE_NO_SCRIPT
Script doesn't exist.
Definition base.h:95
@ REDIS_RCODE_ASK
Attempt operation on an alternative node.
Definition base.h:93
@ REDIS_RCODE_ERROR
Unrecoverable library/server error.
Definition base.h:89
char const * password
to authenticate to Redis.
Definition base.h:117
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.
Definition redis.c:638
uint32_t max_alt
Maximum alternative nodes to try.
Definition base.h:123
uint32_t max_retries
Maximum number of times we attempt a command when receiving successive -TRYAGAIN messages.
Definition base.h:121
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:365
Configuration parameters for a redis connection.
Definition base.h:109
Connection handle, holding a redis context.
Definition base.h:100
Value pair map.
Definition map.h:77
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
int nonnull(2, 5))
static size_t char ** out
Definition value.h:997