The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
io.h
Go to the documentation of this file.
1#pragma once
2
3/*
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19/**
20 * $Id: e0a2679cedda430fdcc811e65b0660f0708db52e $
21 * @file lib/redis/io.h
22 * @brief Redis asynchronous I/O connection allocation
23 *
24 * @copyright 2019 The FreeRADIUS server project
25 * @copyright 2019 Network RADIUS SAS (legal@networkradius.com)
26 *
27 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
28 */
29RCSIDH(redis_io_h, "$Id: e0a2679cedda430fdcc811e65b0660f0708db52e $")
30
31#include "config.h"
32#include <freeradius-devel/redis/base.h>
33#include <freeradius-devel/util/event.h>
34#include <freeradius-devel/server/connection.h>
35
36#ifndef WITH_TLS
37# undef HAVE_REDIS_SSL
38#endif
39
40#ifdef HAVE_REDIS_SSL
41#include <freeradius-devel/tls/strerror.h>
42#endif
43
44#include <hiredis/async.h>
45
46#ifdef __cplusplus
47extern "C" {
48#endif
49
50typedef struct {
51 char const *hostname;
53 uint32_t database; //!< number on Redis server.
54
55 char const *username; //!< to authenticate to Redis.
56 char const *password; //!< to authenticate to Redis.
57 char const *log_prefix;
58 bool use_tls;
60
61typedef uint64_t fr_redis_sqn_t;
62
67
68/** Store I/O state
69 *
70 * There are three layers of wrapping structures
71 *
72 * connection_t -> fr_redis_handle_t -> redisAsyncContext
73 *
74 */
75typedef struct {
76 bool read_set; //!< We're listening for reads.
77 bool write_set; //!< We're listening for writes.
78 bool freeing; //!< Ensure that redisAsyncFree doesn't cause
79 ///< a callback loop.
80 fr_timer_t *timer_ev; //!< Connection timer.
81 fr_event_fd_t *fd_ev; //!< IO event.
82
83
84 redisAsyncContext *ac; //!< Async handle for hiredis.
85
86 fr_dlist_head_t ignore; //!< Contains SQNs for responses that should be ignored.
87
88 fr_redis_sqn_t req_sqn; //!< Current redis request number.
89 ///< Note: It would take 5.8 million years running
90 ///< at 100,000 requests/s to overflow, but my OCD
91 ///< requires that the max uses for trunk connections
92 ///< is set to UINT64_MAX if not specified by
93 ///< the user. It's one branch, and it makes me
94 ///< happy, deal with it.
95 fr_redis_sqn_t rsp_sqn; //!< Current redis response number.
97
98/** Tell the handle we sent a command, and get the SQN that command was assigned
99 *
100 * *MUST* be called for every command sent using the handle. Relies on the fact
101 * that responses from REDIS are FIFO with requests.
102 *
103 * @param[in] h the request was sent on.
104 * @return the handle specific SQN.
105 */
110
111/** Ignore a response with a specific sequence number
112 *
113 * @param[in] h to ignore the response on.
114 * @param[in] sqn the command to ignore.
115 */
117{
118 fr_redis_sqn_ignore_t *ignore, *check = NULL;
119
120 fr_assert(sqn <= h->req_sqn);
121
122 if (sqn < h->rsp_sqn) {
123 DEBUG4("Asked to ignore sequence %"PRIu64", but next expected response is %"PRIu64, sqn, h->rsp_sqn);
124 return;
125 }
126
127 MEM(ignore = talloc_zero(h, fr_redis_sqn_ignore_t));
128 ignore->sqn = sqn;
130 if (!check || check->sqn < sqn) {
131 fr_dlist_insert_tail(&h->ignore, ignore);
132 return;
133 }
134 while ((check = fr_dlist_prev(&h->ignore, check))) {
135 if (check->sqn < sqn) break;
136 }
137 fr_dlist_insert_after(&h->ignore, check, ignore);
138}
139
140/** Update the response sequence number and check if we should ignore the response
141 *
142 * *MUST* be called for every reply received using the handle. Relies on the fact
143 * that responses from REDIS are FIFO with requests.
144 *
145 * @param[in] h to check for ignored responses.
146 */
148{
151
152 fr_assert(h->rsp_sqn <= h->req_sqn); /* Can't have more responses than requests */
153
155 if (!head || (head->sqn > check)) return true; /* First response to ignore is some time after this one */
156 fr_assert(head->sqn == check);
157
160
161 return false;
162}
163
165 connection_conf_t const *conn_conf,
166 fr_redis_io_conf_t const *io_conf,
167#ifdef HAVE_REDIS_SSL
168 SSL_CTX *ssl_ctx,
169#endif
170 char const *log_prefix);
171
172redisAsyncContext *fr_redis_connection_get_async_ctx(connection_t *conn);
173
174#ifdef __cplusplus
175}
176#endif
#define RCSIDH(h, id)
Definition build.h:561
#define MEM(x)
Definition debug.h:38
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition dlist.h:468
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:620
static void * fr_dlist_prev(fr_dlist_head_t const *list_head, void const *ptr)
Get the previous item in a list.
Definition dlist.h:570
static void * fr_dlist_tail(fr_dlist_head_t const *list_head)
Return the TAIL item of a list or NULL if the list is empty.
Definition dlist.h:513
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition dlist.h:360
static int fr_dlist_insert_after(fr_dlist_head_t *list_head, void *pos, void *ptr)
Insert an item after an item already in the list.
Definition dlist.h:396
Head of a doubly linked list.
Definition dlist.h:51
Entry in a doubly linked list.
Definition dlist.h:41
talloc_free(hp)
bool use_tls
Definition io.h:58
redisAsyncContext * fr_redis_connection_get_async_ctx(connection_t *conn)
Return the redisAsyncContext associated with the connection.
Definition io.c:654
fr_redis_sqn_t rsp_sqn
Current redis response number.
Definition io.h:95
bool read_set
We're listening for reads.
Definition io.h:76
redisAsyncContext * ac
Async handle for hiredis.
Definition io.h:84
fr_redis_sqn_t sqn
Definition io.h:65
fr_dlist_head_t ignore
Contains SQNs for responses that should be ignored.
Definition io.h:86
fr_event_fd_t * fd_ev
IO event.
Definition io.h:81
char const * username
to authenticate to Redis.
Definition io.h:55
static void fr_redis_connection_ignore_response(fr_redis_handle_t *h, fr_redis_sqn_t sqn)
Ignore a response with a specific sequence number.
Definition io.h:116
fr_timer_t * timer_ev
Connection timer.
Definition io.h:80
uint32_t database
number on Redis server.
Definition io.h:53
char const * password
to authenticate to Redis.
Definition io.h:56
bool write_set
We're listening for writes.
Definition io.h:77
char const * hostname
Definition io.h:51
connection_t * fr_redis_connection_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, connection_conf_t const *conn_conf, fr_redis_io_conf_t const *io_conf, char const *log_prefix)
Allocate an async redis I/O connection.
Definition io.c:610
char const * log_prefix
Definition io.h:57
fr_dlist_t entry
Definition io.h:64
static bool fr_redis_connection_process_response(fr_redis_handle_t *h)
Update the response sequence number and check if we should ignore the response.
Definition io.h:147
uint16_t port
Definition io.h:52
bool freeing
Ensure that redisAsyncFree doesn't cause a callback loop.
Definition io.h:78
static fr_redis_sqn_t fr_redis_connection_sent_request(fr_redis_handle_t *h)
Tell the handle we sent a command, and get the SQN that command was assigned.
Definition io.h:106
uint64_t fr_redis_sqn_t
Definition io.h:61
fr_redis_sqn_t req_sqn
Current redis request number.
Definition io.h:88
Store I/O state.
Definition io.h:75
#define DEBUG4(_fmt,...)
Definition log.h:272
A file descriptor/filter event.
Definition event.c:260
Stores all information relating to an event list.
Definition event.c:377
unsigned short uint16_t
unsigned int uint32_t
#define fr_assert(_expr)
Definition rad_assert.h:37
void check(const char *name, int index, const struct info *all, int want_lineno, const char *want_function, const char *want_file, int *failed)
Definition testlib.c:72
A timer event.
Definition timer.c:83
static fr_event_list_t * el
static fr_slen_t head
Definition xlat.h:421