All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
redis.h
Go to the documentation of this file.
1 /*
2  * This program is 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: 4d2fb9c1cc2b625064923f60994cc2b2507a7af7 $
19  * @file redis.h
20  * @brief Common functions for interacting with Redis via hiredis
21  *
22  * @author Arran Cudbard-Bell
23  *
24  * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
25  * @copyright 2000,2006,2015 The FreeRADIUS server project
26  * @copyright 2011 TekSavvy Solutions <gabe@teksavvy.com>
27  */
28 
29 #ifndef LIBFREERADIUS_REDIS_H
30 #define LIBFREERADIUS_REDIS_H
31 
32 RCSIDH(redis_h, "$Id: 4d2fb9c1cc2b625064923f60994cc2b2507a7af7 $")
33 
34 #include <freeradius-devel/radiusd.h>
35 #include <hiredis/hiredis.h>
36 
37 #define MAX_REDIS_COMMAND_LEN 4096
38 #define MAX_REDIS_ARGS 16
39 
40 #define REDIS_ERROR_MOVED_STR "MOVED"
41 #define REDIS_ERROR_ASK_STR "ASK"
42 #define REDIS_ERROR_TRY_AGAIN_STR "TRYAGAIN"
43 #define REDIS_ERROR_NO_SCRIPT_STR "NOSCRIPT"
44 #define REDIS_DEFAULT_PORT 6379
45 
46 /** Wrap freeReplyObject so we consistently check for NULL pointers
47  *
48  * Older versions such as 0.10 (which ship with Ubuntu <= 14.10)
49  * don't check for NULL pointer before attempting to free, so we
50  * get a NULL pointer dereference in some cases.
51  *
52  * Rather than go back through the many calls to freeReplyObject
53  * and attempt to determine code paths that may result in it being
54  * called on a NULL pointer, we use this to always check.
55  */
56 #define fr_redis_reply_free(_p) if (_p) freeReplyObject(_p)
57 
58 extern const FR_NAME_NUMBER redis_reply_types[];
59 extern const FR_NAME_NUMBER redis_rcodes[];
60 
61 /** Codes are ordered inversely by priority
62  *
63  * To simplify handling the return codes from pipelined commands,
64  * the lowest status code, and the reply which accompanies it should
65  * be returned to the redis cluster code.
66  */
67 typedef enum {
68  REDIS_RCODE_SUCCESS = 0, //!< Operation was successfull.
69  REDIS_RCODE_ERROR = -1, //!< Unrecoverable library/server error.
70  REDIS_RCODE_TRY_AGAIN = -2, //!< Try the operation again.
71  REDIS_RCODE_RECONNECT = -3, //!< Transitory error, caller should retry the operation
72  //!< with a new connection.
73  REDIS_RCODE_ASK = -4, //!< Attempt operation on an alternative node.
74  REDIS_RCODE_MOVE = -5, //!< Attempt operation on an alternative node with remap.
75  REDIS_RCODE_NO_SCRIPT = -6, //!< Script doesn't exist.
77 
78 /** Connection handle, holding a redis context
79  */
80 typedef struct redis_conn {
81  redisContext *handle; //!< Hiredis context used when issuing commands.
83 
84 /** Configuration parameters for a redis connection
85  *
86  * @note should be passed as instance data to #module_connection_pool_init.
87  */
88 typedef struct redis_common_conf {
89  char const *prefix; //!< Logging prefix for errors in #fr_redis_cluster_conn_create.
90 
91  char const **hostname; //!< of Redis server.
92  uint16_t port; //!< of Redis daemon.
93  uint32_t database; //!< number on Redis server.
94 
95  char const *password; //!< to authenticate to Redis.
96 
97  uint8_t max_nodes; //!< Maximum number of cluster nodes to connect to.
98  uint32_t max_redirects; //!< Maximum number of times we can be redirected.
99  uint32_t max_retries; //!< Maximum number of times we attempt a command
100  //!< when receiving successive -TRYAGAIN messages.
101  uint32_t max_alt; //!< Maximum alternative nodes to try.
102  struct timeval retry_delay; //!< How long to wait when we received a -TRYAGAIN
103  //!< message.
105 
106 #define REDIS_COMMON_CONFIG \
107  { FR_CONF_OFFSET("server", PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_MULTI, fr_redis_conf_t, hostname) }, \
108  { FR_CONF_OFFSET("port", PW_TYPE_SHORT, fr_redis_conf_t, port), .dflt = "6379" }, \
109  { FR_CONF_OFFSET("database", PW_TYPE_INTEGER, fr_redis_conf_t, database), .dflt = "0" }, \
110  { FR_CONF_OFFSET("password", PW_TYPE_STRING | PW_TYPE_SECRET, fr_redis_conf_t, password) }, \
111  { FR_CONF_OFFSET("max_nodes", PW_TYPE_BYTE, fr_redis_conf_t, max_nodes), .dflt = "20" }, \
112  { FR_CONF_OFFSET("max_alt", PW_TYPE_INTEGER, fr_redis_conf_t, max_alt), .dflt = "3" }, \
113  { FR_CONF_OFFSET("max_redirects", PW_TYPE_INTEGER, fr_redis_conf_t, max_redirects), .dflt = "2" }
114 
115 void fr_redis_version_print(void);
116 
117 /*
118  * Command and resulting parsing
119  */
121 
122 void fr_redis_reply_print(log_lvl_t lvl, redisReply *reply, REQUEST *request, int idx);
123 
124 int fr_redis_reply_to_value_data(TALLOC_CTX *ctx, value_data_t *out, redisReply *reply,
125  PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv);
126 
127 int fr_redis_reply_to_map(TALLOC_CTX *ctx, vp_map_t **out,
128  REQUEST *request, redisReply *key, redisReply *op, redisReply *value);
129 
130 int fr_redis_tuple_from_map(TALLOC_CTX *pool, char const *out[], size_t out_len[], vp_map_t *map);
131 
132 fr_redis_rcode_t fr_redis_get_version(char *out, size_t out_len, fr_redis_conn_t *conn);
133 
134 uint32_t fr_redis_version_num(char const *version);
135 
136 /*
137  * Process response from pipelined command.
138  */
139 fr_redis_rcode_t fr_redis_pipeline_result(fr_redis_rcode_t *rcode, redisReply *out[], size_t out_len,
140  fr_redis_conn_t *conn, int pipelined);
141 
142 #define fr_redis_pipeline_free(_r, _n) \
143 do {\
144  size_t _i; \
145  for (_i = 0; _i < _n; _i++) {\
146  fr_redis_reply_free(_r[_i]); \
147  _r[_i] = NULL; \
148  } \
149 } while (0)
150 #endif /* LIBFREERADIUS_REDIS_H */
char const ** hostname
of Redis server.
Definition: redis.h:91
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.
Definition: redis.c:460
#define RCSIDH(h, id)
Definition: build.h:136
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.
Definition: redis.c:197
Configuration parameters for a redis connection.
Definition: redis.h:88
Dictionary attribute.
Definition: dict.h:77
Script doesn't exist.
Definition: redis.h:75
const FR_NAME_NUMBER redis_reply_types[]
Definition: redis.c:29
uint32_t fr_redis_version_num(char const *version)
Convert version string into a 32bit unsigned integer for comparisons.
Definition: redis.c:597
char const * prefix
Logging prefix for errors in fr_redis_cluster_conn_create.
Definition: redis.h:89
static expr_map_t map[]
Definition: rlm_expr.c:169
uint32_t database
number on Redis server.
Definition: redis.h:93
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.
Definition: redis.c:381
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:549
unsigned int version
Definition: proto_bfd.c:192
redisContext * handle
Hiredis context used when issuing commands.
Definition: redis.h:81
Unrecoverable library/server error.
Definition: redis.h:69
const FR_NAME_NUMBER redis_rcodes[]
Definition: redis.c:39
Attempt operation on an alternative node.
Definition: redis.h:73
uint16_t port
of Redis daemon.
Definition: redis.h:92
void fr_redis_reply_print(log_lvl_t lvl, redisReply *reply, REQUEST *request, int idx)
Print the response data in a useful treelike form.
Definition: redis.c:139
char const * password
to authenticate to Redis.
Definition: redis.h:95
uint32_t max_alt
Maximum alternative nodes to try.
Definition: redis.h:101
uint32_t max_retries
Maximum number of times we attempt a command when receiving successive -TRYAGAIN messages.
Definition: redis.h:99
Attempt operation on an alternative node with remap.
Definition: redis.h:74
uint8_t max_nodes
Maximum number of cluster nodes to connect to.
Definition: redis.h:97
enum log_lvl log_lvl_t
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
Definition: redis.c:52
Transitory error, caller should retry the operation with a new connection.
Definition: redis.h:71
Try the operation again.
Definition: redis.h:70
uint32_t max_redirects
Maximum number of times we can be redirected.
Definition: redis.h:98
struct redis_conn fr_redis_conn_t
Connection handle, holding a redis context.
fr_redis_rcode_t
Codes are ordered inversely by priority.
Definition: redis.h:67
struct redis_common_conf fr_redis_conf_t
Configuration parameters for a redis connection.
struct timeval retry_delay
How long to wait when we received a -TRYAGAIN message.
Definition: redis.h:102
Operation was successfull.
Definition: redis.h:68
fr_redis_rcode_t fr_redis_command_status(fr_redis_conn_t *conn, redisReply *reply)
Check the reply for errors.
Definition: redis.c:76
Value pair map.
Definition: map.h:46
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.
Definition: redis.c:282
Connection handle, holding a redis context.
Definition: redis.h:80
PW_TYPE
Internal data types used within libfreeradius.
Definition: radius.h:31