The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
io.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: 7c6edcd36d2ebd58261d56de325a0e3d462ffb48 $
19 * @file lib/redis/io.c
20 * @brief Common functions for interacting with Redis via hiredis
21 *
22 * @copyright 2019 The FreeRADIUS server project
23 * @copyright 2019 Network RADIUS SAS (legal@networkradius.com)
24 *
25 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
26 */
27
28#include <freeradius-devel/redis/io.h>
29#include <freeradius-devel/util/debug.h>
30
31#ifdef HAVE_REDIS_SSL
32#include <hiredis/hiredis_ssl.h>
33#endif
34
35typedef struct {
37#ifdef HAVE_REDIS_SSL
38 SSL_CTX *ssl_ctx;
39#endif
41
42/** Called by hiredis to indicate the connection is dead
43 *
44 */
45static void _redis_disconnected(redisAsyncContext const *ac, UNUSED int status)
46{
47 connection_t *conn = talloc_get_type_abort(ac->data, connection_t);
48 fr_redis_handle_t *h = conn->h;
49
50 /*
51 * Some code paths result in hiredis calling this callback after
52 * we have freed the handle, which would result in a use after free.
53 * or we do not actually want to reconnnect.
54 */
55 switch (conn->state) {
58 return;
59
60 default:
61 break;
62 }
63
64 /*
65 * redisAsyncFree was called with a live
66 * connection, but inside the talloc
67 * destructor of the fr_redis_handle_t.
68 *
69 * Don't signal the connection state
70 * machine that it needs reconnecting,
71 * the connection is being destroyed.
72 */
73 if (h->freeing) return;
74
75 DEBUG4("Signalled by hiredis, connection disconnected");
76
78}
79
80/** Callback for verifying the results of SELECT
81 *
82 */
83static void _redis_select_result(struct redisAsyncContext *ac, void *data, UNUSED void *privdata)
84{
85 connection_t *conn = talloc_get_type_abort(ac->data, connection_t);
86 redisReply *reply = data;
87
88 if (!reply) {
89 ERROR("Failed selecting database: %s", ac->errstr);
90 error:
92 return;
93 }
94
95 switch (reply->type) {
96 case REDIS_REPLY_STATUS:
97 if (strcmp(reply->str, "OK") != 0) {
98 ERROR("Failed selecting database: %s", reply->str);
99 goto error;
100 }
101 break; /* else it's OK */
102
103 case REDIS_REPLY_ERROR:
104 ERROR("Failed selecting database: %s", reply->str);
105 goto error;
106
107 default:
108 ERROR("Unexpected reply of type %s to SELECT",
109 fr_table_str_by_value(redis_reply_types, reply->type, "<UNKNOWN>"));
110 goto error;
111 }
112
114}
115
116/** Callback for verifying the results of AUTH
117 *
118 */
119static void _redis_auth_result(struct redisAsyncContext *ac, void *data, UNUSED void *privdata)
120{
121 connection_t *conn = talloc_get_type_abort(ac->data, connection_t);
122 redisReply *reply = data;
123 redis_conn_uctx_t *conn_uctx = connection_uctx_get(conn);
124 uint32_t database = conn_uctx->io_conf->database;
125
126 if (!reply) {
127 ERROR("Failed authenticating: %s", ac->errstr);
128 error:
130 return;
131 }
132
133 switch (reply->type) {
134 case REDIS_REPLY_STATUS:
135 if (strcmp(reply->str, "OK") != 0) {
136 ERROR("Failed authenticating: %s", reply->str);
137 goto error;
138 }
139 break; /* else it's OK */
140
141 case REDIS_REPLY_ERROR:
142 ERROR("Failed authenticating: %s", reply->str);
143 goto error;
144
145 default:
146 ERROR("Unexpected reply of type %s to AUTH",
147 fr_table_str_by_value(redis_reply_types, reply->type, "<UNKNOWN>"));
148 goto error;
149 }
150
151 if (database) {
152 DEBUG3("Executing: SELECT %d", database);
153 if (redisAsyncCommand(ac, _redis_select_result, NULL, "SELECT %d", database) != REDIS_OK) goto error;
154 return;
155 }
156
158}
159
160/** Called by hiredis to indicate the connection is live
161 *
162 */
163static void _redis_connected_nc(redisAsyncContext *ac, UNUSED int status)
164{
165 connection_t *conn = talloc_get_type_abort(ac->data, connection_t);
166 redis_conn_uctx_t *conn_uctx = connection_uctx_get(conn);
167 fr_redis_io_conf_t const *io_conf = conn_uctx->io_conf;
168
169 DEBUG4("Signalled by hiredis, connection is open");
170
171#ifdef HAVE_REDIS_SSL
172 if (io_conf->use_tls) {
173 fr_tls_session_t *tls_session = fr_tls_session_alloc_client(conn, conn_uctx->ssl_ctx);
174 DEBUG2("%s - Using tls", io_conf->log_prefix);
175 if (!tls_session) {
176 fr_tls_strerror_printf("%s - [%s]", io_conf->log_prefix, conn->name);
177 ERROR("%s - Failed to allocate TLS session", io_conf->log_prefix);
179 return;
180 }
181
182 // redisInitiateSSL() takes ownership of SSL object on success
183 SSL_up_ref(tls_session->ssl);
184 if (redisInitiateSSL(&ac->c, tls_session->ssl) != REDIS_OK) {
185 ERROR("%s - Failed to initiate SSL: %s", io_conf->log_prefix, ac->c.errstr);
186 SSL_free(tls_session->ssl);
188 return;
189 }
190 }
191#endif
192
193 /*
194 * If auth is configured, send the appropriate AUTH command
195 * before marking the connection as connected.
196 */
197 if (io_conf->password) {
198 if (io_conf->username) {
199 DEBUG3("Executing: AUTH %s %s", io_conf->username, io_conf->password);
200 if (redisAsyncCommand(ac, _redis_auth_result, NULL, "AUTH %s %s",
201 io_conf->username, io_conf->password) != REDIS_OK) {
202 error:
203 ERROR("Failed executing command");
205 }
206 return;
207 }
208 DEBUG3("Executing: AUTH %s", io_conf->password);
209 if (redisAsyncCommand(ac, _redis_auth_result, NULL, "AUTH %s", io_conf->password) != REDIS_OK) goto error;
210 return;
211 }
212
213 if (io_conf->database) {
214 DEBUG3("Executing: SELECT %d", io_conf->database);
215 if (redisAsyncCommand(ac, _redis_select_result, NULL, "SELECT %d", io_conf->database) != REDIS_OK) goto error;
216 return;
217 }
218
220}
221
222#ifndef HAVE_REDIS_CALLBACKNC
223/*
224 * Hiredis prior to 1.1.0 only has the callback with const context
225 * We need it un-const so we can update the connection status.
226 */
227static void _redis_connected(redisAsyncContext const *ac, int status)
228{
229 redisAsyncContext *our_ac = UNCONST(redisAsyncContext *, ac);
230
231 _redis_connected_nc(our_ac, status);
232}
233#endif
234
235/** Redis FD became readable
236 *
237 */
238static void _redis_io_service_readable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
239{
241 fr_redis_handle_t *h = conn->h;
242
243 DEBUG4("redis handle %p - FD %i now readable", h, fd);
244
245 redisAsyncHandleRead(h->ac);
246}
247
248/** Redis FD became writable
249 *
250 */
251static void _redis_io_service_writable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
252{
254 fr_redis_handle_t *h = conn->h;
255
256 DEBUG4("redis handle %p - FD %i now writable", h, fd);
257
258 redisAsyncHandleWrite(h->ac);
259}
260
261static void _redis_io_common(connection_t *conn, fr_redis_handle_t *h, bool read, bool write);
262
263/** Redis FD errored - Automatically removes registered events
264 *
265 */
267 int fd_errno, void *uctx)
268{
269 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
270 fr_redis_handle_t *h = conn->h;
271
272 ERROR("%s handle %p - FD %i errored: %s", conn->name, h, fd, fr_syserror(fd_errno));
273
274 /*
275 * Ensure fd events are removed - hiredis doesn't clean up quickly.
276 */
277 _redis_io_common(conn, h, false, false);
278
279 /*
280 * Connection state machine will handle reconnecting
281 */
283}
284
285/** Deal with the method hiredis uses to register/unregister interest in a file descriptor
286 *
287 */
288static void _redis_io_common(connection_t *conn, fr_redis_handle_t *h, bool read, bool write)
289{
290 redisContext *c = &(h->ac->c);
291 fr_event_list_t *el = conn->el;
292
293 /*
294 * hiredis doesn't even attempt to dedup registration
295 * requests *sigh*...
296 */
297 if ((h->read_set == read) && (h->write_set == write)) return;
298
299 if (!read && !write) {
300 DEBUG4("redis handle %p - De-registering FD %i", h, c->fd);
301
303 PERROR("redis handle %p - De-registration failed for FD %i", h, c->fd);
304 }
305 h->fd_ev = NULL;
306 return;
307 }
308
309 DEBUG4("redis handle %p - Registered for %s%serror events on FD %i",
310 h, read ? "read+" : "", write ? "write+" : "", c->fd);
311
312 if (fr_event_fd_insert(h, &h->fd_ev, el, c->fd,
313 read ? _redis_io_service_readable : NULL,
314 write ? _redis_io_service_writable : NULL,
316 conn) < 0) {
317 PERROR("redis handle %p - Registration failed for %s%serror events on FD %i",
318 h, read ? "read+" : "", write ? "write+" : "", c->fd);
319 return;
320 }
321
322 h->read_set = read;
323 h->write_set = write;
324}
325
326/** Register FD for reads
327 *
328 */
329static void _redis_io_add_read(void *uctx)
330{
331 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
332 fr_redis_handle_t *h = conn->h;
333
334 _redis_io_common(conn, h, true, h->write_set);
335}
336
337/** De-register FD for reads
338 *
339 */
340static void _redis_io_del_read(void *uctx)
341{
342 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
343 fr_redis_handle_t *h = conn->h;
344
345 _redis_io_common(conn, h, false, h->write_set);
346}
347
348/** Register FD for writes
349 *
350 */
351static void _redis_io_add_write(void *uctx)
352{
353 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
354 fr_redis_handle_t *h = conn->h;
355
356 _redis_io_common(conn, h, h->read_set, true);
357}
358
359/** De-register FD for writes
360 *
361 */
362static void _redis_io_del_write(void *uctx)
363{
364 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
365 fr_redis_handle_t *h = conn->h;
366
367 _redis_io_common(conn, h, h->read_set, false);
368}
369
370#ifdef HAVE_REDIS_TIMEOUT
371/** Connection timer expired
372 *
373 */
374static void _redis_io_service_timer_expired(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
375{
377 fr_redis_handle_t *h = conn->h;
378
379 DEBUG4("redis handle %p - Timeout", h);
380
381 redisAsyncHandleTimeout(h->ac);
382}
383
384/** Modify the connection I/O timer
385 *
386 */
387static void _redis_io_timer_modify(void *uctx, struct timeval tv)
388{
389 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
390 fr_redis_handle_t *h = conn->h;
391 fr_time_delta_t timeout;
392
393 timeout = fr_time_delta_from_timeval(&tv);
394
395 DEBUG4("redis handle %p - Timeout in %pV seconds", h, fr_box_time_delta(timeout));
396
397 if (fr_timer_in(h, conn->el->tl, &h->timer_ev, timeout,
398 false, _redis_io_service_timer_expired, conn) < 0) {
399 PERROR("redis timeout %p - Failed adding timeout", h);
400 }
401}
402#endif
403
404/** Handle freeing the redisAsyncContext
405 *
406 * delRead and delWrite don't seem to be called when the redisAsyncContext is freed
407 *
408 * As the IO events must be removed from the event loop *before* the FD is closed
409 * and as the IO events will only be automatically de-registered when when the
410 * fr_redis_handle_t is freed.
411 *
412 * Unfortunately the destructor for the fr_redis_handle_t will be run before
413 * the IO events are de-registered, which'll free the redisAsycCtx, which'll close
414 * the FD.
415 *
416 * This means there'd be a brief period of time between the FD is closed, and
417 * it being removed from the event loop.
418 *
419 * We use the cleanup callback (which is called before the FD is closed) to remove
420 * the events now, and ensure there's no chance of issues.
421 */
422static void _redis_io_free(void *uctx)
423{
424 connection_t *conn = talloc_get_type_abort(uctx, connection_t);
425 fr_redis_handle_t *h = conn->h;
426
427 /*
428 * Some code paths result in hiredis calling this callback after
429 * we have freed the handle, which would result in a use after free.
430 */
431 if (conn->state == CONNECTION_STATE_CLOSED) return;
432
433 DEBUG4("redis handle %p - Freed", h);
434
435 _redis_io_common(conn, h, false, false);
436 h->ac = NULL;
437}
438
439/** Configures async I/O callbacks for an existing redisAsyncContext
440 *
441 */
442static int fr_redis_io_setup(redisAsyncContext *ac, connection_t const *conn)
443{
444 if (ac->ev.data != NULL) return REDIS_ERR;
445
446 ac->ev.addRead = _redis_io_add_read;
447 ac->ev.delRead = _redis_io_del_read;
448 ac->ev.addWrite = _redis_io_add_write;
449 ac->ev.delWrite = _redis_io_del_write;
450#ifdef HAVE_REDIS_TIMEOUT
451 ac->ev.scheduleTimer = _redis_io_timer_modify;
452#endif
453 ac->ev.cleanup = _redis_io_free;
454 memcpy(&ac->ev.data, &conn, sizeof(ac->ev.data));
455
456 return REDIS_OK;
457}
458
459/** Free the redis async context when the handle is freed
460 *
461 */
463{
464 /*
465 * Don't fire the reconnect callback if we're
466 * freeing the handle.
467 */
468 h->freeing = true;
469 if (h->ac) redisAsyncFree(h->ac);
470
471 return 0;
472}
473
474/** Callback for the initialise state
475 *
476 * Should attempt to open a non-blocking connection and return it in h_out.
477 *
478 * @param[out] h_out Where to write the new handle
479 * @param[in] conn This connection. Opaque, should only be used for
480 * signalling the connection state machine.
481 * @param[in] uctx User context.
482 * @return
483 * - #CONNECTION_STATE_CONNECTING if a file descriptor was successfully created.
484 * - #CONNECTION_STATE_FAILED if we could not open a valid handle.
485 */
486CC_NO_UBSAN(function) /* UBSAN: false positive - public vs private connection_t trips --fsanitize=function*/
487static connection_state_t _redis_io_connection_init(void **h_out, connection_t *conn, void *uctx)
488{
489 redis_conn_uctx_t *conn_uctx = uctx;
490 char const *host = conn_uctx->io_conf->hostname;
491 uint16_t port = conn_uctx->io_conf->port;
493 int ret;
494
495 /*
496 * Allocate a structure to wrap the
497 * redis async context.
498 */
499 MEM(h = talloc_zero(conn, fr_redis_handle_t));
500 talloc_set_destructor(h, _redis_handle_free);
501
502 h->ac = redisAsyncConnect(host, port);
503 if (!h->ac) {
504 ERROR("Failed allocating handle for %s:%u", host, port);
506 }
507
508 if (h->ac->err) {
509 ERROR("Failed allocating handle for %s:%u: %s", host, port, h->ac->errstr);
510 error:
511 redisAsyncFree(h->ac);
512 h->ac = NULL;
514 }
515
516 /*
517 * Store the connection in private data,
518 * so we can use it for signalling.
519 *
520 * Comments in the redis src indicate
521 * it doesn't mess with this.
522 */
523 memcpy(&h->ac->data, &conn, sizeof(h->ac->data));
524
525 /*
526 * Handle has to be associated with the
527 * conn in case I/O handlers want to get
528 * at it.
529 */
530 *h_out = h;
531
532 /*
533 * Install the I/O service functions
534 *
535 * Event library must be set first
536 * before calling redisAsyncSetConnectCallback
537 * as just setting the callback triggers
538 * I/O events to be registered.
539 */
540 fr_redis_io_setup(h->ac, conn);
541
542 /*
543 * Setup callbacks so we're notified
544 * when the connection state changes.
545 *
546 * We then signal the connection state
547 * machine, to let it handle
548 * reconnecting.
549 */
550#ifdef HAVE_REDIS_CALLBACKNC
551 ret = redisAsyncSetConnectCallbackNC(h->ac, _redis_connected_nc);
552#else
553 ret = redisAsyncSetConnectCallback(h->ac, _redis_connected);
554#endif
555 if (ret != REDIS_OK) {
556 ERROR("Failed setting connected callback: Error %i", ret);
557 goto error;
558 }
559
560 ret = redisAsyncSetDisconnectCallback(h->ac, _redis_disconnected);
561 if (ret != REDIS_OK) {
562 ERROR("Failed setting disconnected callback: Error %i", ret);
563 goto error;
564 }
565
567
569}
570
571/** Gracefully signal that the connection should shutdown
572 *
573 */
575{
576 fr_redis_handle_t *our_h = talloc_get_type_abort(h, fr_redis_handle_t);
577
578 redisAsyncDisconnect(our_h->ac); /* Should not free the handle */
579
581}
582
583/** Notification that the connection has errored and must be closed
584 *
585 * This should be used to close the file descriptor. It is assumed
586 * that the file descriptor is invalid after this callback has been executed.
587 *
588 * If this callback does not close the file descriptor, the server will leak
589 * file descriptors.
590 *
591 * @param[in] el to remove event handlers from.
592 * @param[in] h to close.
593 * @param[in] uctx User context.
594 */
596{
597 fr_redis_handle_t *our_h = talloc_get_type_abort(h, fr_redis_handle_t);
598
599 /*
600 * The destructor will free the redisAsyncContext
601 * which'll close the connection, after removing
602 * it from the event loop.
603 */
604 talloc_free(our_h);
605}
606
607/** Allocate an async redis I/O connection
608 *
609 */
611 fr_redis_io_conf_t const *io_conf,
612#ifdef HAVE_REDIS_SSL
613 SSL_CTX *ssl_ctx,
614#endif
615 char const *log_prefix)
616{
617 connection_t *conn;
618 redis_conn_uctx_t *uctx;
619
620 MEM(uctx = talloc(ctx, redis_conn_uctx_t));
621 uctx->io_conf = io_conf;
622#ifdef HAVE_REDIS_SSL
623 uctx->ssl_ctx = ssl_ctx;
624#endif
625
626 /*
627 * We don't specify an open callback
628 * as hiredis handles switching over
629 * all the I/O handlers internally
630 * within hireds, and calls us when
631 * the connection is open.
632 */
633 conn = connection_alloc(ctx, el,
638 },
639 conn_conf,
640 log_prefix,
641 uctx);
642 if (!conn) return NULL;
643
644 return conn;
645}
646
647/** Return the redisAsyncContext associated with the connection
648 *
649 * This is needed to issue commands to the redis server.
650 *
651 * @param[in] conn To retrieve async ctx from.
652 * @return The async ctx.
653 */
655{
656 fr_redis_handle_t *h = conn->h;
657 return h->ac;
658}
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define CC_NO_UBSAN(_sanitize)
Definition build.h:503
#define UNUSED
Definition build.h:384
connection_state_t
Definition connection.h:47
@ CONNECTION_STATE_FAILED
Connection has failed.
Definition connection.h:56
@ CONNECTION_STATE_CLOSED
Connection has been closed.
Definition connection.h:57
@ CONNECTION_STATE_CONNECTING
Waiting for connection to establish.
Definition connection.h:52
@ CONNECTION_STATE_SHUTDOWN
Connection is shutting down.
Definition connection.h:55
@ CONNECTION_FAILED
Connection is being reconnected because it failed.
Definition connection.h:89
Holds a complete set of functions for a connection.
Definition connection.h:199
#define MEM(x)
Definition debug.h:38
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:257
#define fr_event_fd_insert(...)
Definition event.h:247
talloc_free(hp)
static void _redis_io_service_errored(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, int fd_errno, void *uctx)
Redis FD errored - Automatically removes registered events.
Definition io.c:266
static void _redis_io_del_write(void *uctx)
De-register FD for writes.
Definition io.c:362
redisAsyncContext * fr_redis_connection_get_async_ctx(connection_t *conn)
Return the redisAsyncContext associated with the connection.
Definition io.c:654
static void _redis_io_del_read(void *uctx)
De-register FD for reads.
Definition io.c:340
static int _redis_handle_free(fr_redis_handle_t *h)
Free the redis async context when the handle is freed.
Definition io.c:462
static void _redis_io_add_write(void *uctx)
Register FD for writes.
Definition io.c:351
static connection_state_t _redis_io_connection_shutdown(UNUSED fr_event_list_t *el, void *h, UNUSED void *uctx)
Gracefully signal that the connection should shutdown.
Definition io.c:574
static void _redis_io_service_writable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
Redis FD became writable.
Definition io.c:251
static void _redis_select_result(struct redisAsyncContext *ac, void *data, UNUSED void *privdata)
Callback for verifying the results of SELECT.
Definition io.c:83
static connection_state_t _redis_io_connection_init(void **h_out, connection_t *conn, void *uctx)
Callback for the initialise state.
Definition io.c:487
static void _redis_io_free(void *uctx)
Handle freeing the redisAsyncContext.
Definition io.c:422
fr_redis_io_conf_t const * io_conf
Definition io.c:36
static void _redis_connected_nc(redisAsyncContext *ac, UNUSED int status)
Called by hiredis to indicate the connection is live.
Definition io.c:163
static void _redis_auth_result(struct redisAsyncContext *ac, void *data, UNUSED void *privdata)
Callback for verifying the results of AUTH.
Definition io.c:119
static void _redis_io_service_readable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
Redis FD became readable.
Definition io.c:238
static void _redis_connected(redisAsyncContext const *ac, int status)
Definition io.c:227
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
static void _redis_io_add_read(void *uctx)
Register FD for reads.
Definition io.c:329
static int fr_redis_io_setup(redisAsyncContext *ac, connection_t const *conn)
Configures async I/O callbacks for an existing redisAsyncContext.
Definition io.c:442
static void _redis_disconnected(redisAsyncContext const *ac, UNUSED int status)
Called by hiredis to indicate the connection is dead.
Definition io.c:45
static void _redis_io_common(connection_t *conn, fr_redis_handle_t *h, bool read, bool write)
Deal with the method hiredis uses to register/unregister interest in a file descriptor.
Definition io.c:288
static void _redis_io_connection_close(UNUSED fr_event_list_t *el, void *h, UNUSED void *uctx)
Notification that the connection has errored and must be closed.
Definition io.c:595
bool use_tls
Definition io.h:58
bool read_set
We're listening for reads.
Definition io.h:76
redisAsyncContext * ac
Async handle for hiredis.
Definition io.h:84
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
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
char const * log_prefix
Definition io.h:57
uint16_t port
Definition io.h:52
bool freeing
Ensure that redisAsyncFree doesn't cause a callback loop.
Definition io.h:78
Store I/O state.
Definition io.h:75
#define PERROR(_fmt,...)
Definition log.h:233
#define DEBUG3(_fmt,...)
Definition log.h:271
#define DEBUG4(_fmt,...)
Definition log.h:272
int fr_event_fd_delete_handle(fr_event_fd_t *ef)
Remove a file descriptor from the event loop, by handle.
Definition event.c:1228
Stores all information relating to an event list.
Definition event.c:377
unsigned short uint16_t
unsigned int uint32_t
#define DEBUG2(fmt,...)
fr_table_num_sorted_t const redis_reply_types[]
Definition redis.c:31
void * connection_uctx_get(connection_t *conn)
void connection_signal_reconnect(connection_t *conn, connection_reason_t reason)
Asynchronously signal the connection should be reconnected.
connection_t * connection_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, connection_funcs_t const *funcs, connection_conf_t const *conf, char const *log_prefix, void const *uctx)
Allocate a new connection.
void connection_signal_connected(connection_t *conn)
Asynchronously signal that the connection is open.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
#define talloc_get_type_abort_const
Definition talloc.h:117
static fr_time_delta_t fr_time_delta_from_timeval(struct timeval const *tv)
Definition time.h:597
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
"server local" time.
Definition time.h:69
An event timer list.
Definition timer.c:49
#define fr_timer_in(...)
Definition timer.h:87
static fr_event_list_t * el
static fr_slen_t data
Definition value.h:1340
#define fr_box_time_delta(_val)
Definition value.h:366