28 #include <freeradius-devel/server/connection.h>
29 #include <freeradius-devel/server/trunk.h>
182 talloc_free_children(cmds);
183 memset(&cmds, 0,
sizeof(cmds));
216 #define COMMAND_PRE_ALLOC_COUNT 8
217 #define COMMAND_PRE_ALLOC_LEN 64
293 char const *cmd_str,
size_t cmd_len)
309 switch (tolower(cmd_str[0])) {
311 if (tolower(cmd_str[1] !=
'u'))
break;
312 if (
strncasecmp(cmd_str,
"multi",
sizeof(
"multi") - 1) != 0)
break;
331 if (tolower(cmd_str[1] !=
'e'))
break;
332 if (
strncasecmp(cmd_str,
"exec",
sizeof(
"exec") - 1) != 0)
break;
341 if (tolower(cmd_str[1] !=
'i'))
break;
342 if (
strncasecmp(cmd_str,
"discard",
sizeof(
"discard") - 1) != 0)
break;
353 if (tolower(cmd_str[1] !=
'a'))
break;
354 if (
strncasecmp(cmd_str,
"watch",
sizeof(
"watch") - 1) != 0)
break;
395 ERROR(
"Refusing to enqueue - Unbalanced transaction start/stop commands");
433 redisReply *reply = vreply;
438 DEBUG4(
"Ignoring response with SQN %"PRIu64, (h->
rsp_sqn - 1));
466 char const *log_prefix,
void *
uctx)
633 if (!rtrunk->
trunk) {
653 MEM(our_tconf = talloc_memdup(cluster_thread, tconf,
sizeof(*tconf)));
656 cluster_thread->
el =
el;
657 cluster_thread->
tconf = our_tconf;
659 return cluster_thread;
#define fr_atexit_thread_local(_name, _free, _uctx)
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
fr_dcursor_eval_t void const * uctx
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
static bool fr_dlist_entry_in_list(fr_dlist_t const *entry)
Check if a list entry is part of a list.
static void fr_dlist_entry_unlink(fr_dlist_t *entry)
Remove an item from the dlist when we don't have access to the head.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
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.
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
static int fr_dlist_move(fr_dlist_head_t *list_dst, fr_dlist_head_t *list_src)
Merge two lists, inserting the source at the tail of the destination.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
#define fr_dlist_talloc_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
static void fr_dlist_entry_init(fr_dlist_t *entry)
Initialise a linked list without metadata.
Head of a doubly linked list.
Entry in a doubly linked list.
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.
fr_redis_sqn_t rsp_sqn
Current redis response number.
redisAsyncContext * ac
Async handle for hiredis.
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.
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.
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.
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Stores all information relating to an event list.
int strncasecmp(char *s1, char *s2, int n)
Function prototypes and datatypes for the REST (HTTP) transport.
request_t * request
Request this commands set is associated with (if any).
static int _command_set_free_list_free_on_exit(void *arg)
Free any free requests when the thread is joined.
fr_redis_cluster_thread_t * cluster
Cluster this trunk belongs to.
fr_dlist_head_t sent
Commands sent.
uint16_t txn_start
Number of times a transaction block was started in this command set.
fr_redis_io_conf_t const * io_conf
Redis I/O configuration.
trunk_conf_t const * tconf
Configuration for all trunks in the cluster.
trunk_t * trunk
Trunk containing all the connections to a specific.
fr_redis_cluster_thread_t * fr_redis_cluster_thread_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, trunk_conf_t const *tconf)
Allocate per-thread, per-cluster instance.
fr_redis_command_set_t * fr_redis_command_set_alloc(TALLOC_CTX *ctx, request_t *request, fr_redis_command_set_complete_t complete, fr_redis_command_set_fail_t fail, void *rctx)
Allocate a new command set.
fr_dlist_t entry
Entry in the command buffer.
#define COMMAND_PRE_ALLOC_COUNT
void * rctx
Resume context to write results to.
uint64_t sqn
The sequence number of the command.
fr_redis_command_set_complete_t complete
Notify the creator of the command set that the command set has executed to to completion.
fr_redis_command_set_fail_t fail
Notify the creator of the command set that the command set failed to execute to completion.
char * log_prefix
Common log prefix to use for all cluster related messages.
uint16_t txn_end
The number of times a transaction block ended in this command set.
fr_redis_pipeline_status_t redis_command_set_enqueue(fr_redis_trunk_t *rtrunk, fr_redis_command_set_t *cmds)
Enqueue a command set on a specific trunk.
static int _redis_command_free(fr_redis_command_t *cmd)
Free any result associated with the command.
static void _redis_pipeline_demux(struct redisAsyncContext *ac, void *vreply, void *privdata)
Callback for for receiving Redis replies.
#define COMMAND_PRE_ALLOC_LEN
char const * str
The command string.
static connection_t * _redis_pipeline_connection_alloc(trunk_connection_t *tconn, fr_event_list_t *el, connection_conf_t const *conf, char const *log_prefix, void *uctx)
bool delay_start
Prevent connections from spawning immediately.
redisReply * fr_redis_command_get_result(fr_redis_command_t *cmd)
static void _redis_pipeline_command_set_free(UNUSED request_t *request, void *preq, UNUSED void *uctx)
Free the command set.
static _Thread_local fr_dlist_head_t * command_set_free_list
The thread local free list.
redisReply * result
The result from the REDIS server.
static void _redis_pipeline_command_set_cancel(connection_t *conn, UNUSED trunk_request_t *treq, void *preq, trunk_cancel_reason_t reason, UNUSED void *uctx)
Deal with cancellation of sent requests.
fr_redis_command_type_t type
Redis command type.
static int _redis_command_set_free(fr_redis_command_set_t *cmds)
Free a command set.
static void _redis_pipeline_command_set_complete(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED void *uctx)
Signal the API client that we got a complete set of responses to a command set.
static void _redis_pipeline_command_set_fail(UNUSED request_t *request, void *preq, UNUSED void *rctx, UNUSED void *uctx)
Signal the API client that we failed enqueuing the commands.
bool txn_watch
Transaction was started with a watch statement.
fr_redis_pipeline_status_t fr_redis_command_preformatted_add(fr_redis_command_set_t *cmds, char const *cmd_str, size_t cmd_len)
Add a preformatted/expanded command to the command set.
fr_dlist_head_t completed
Commands complete with replies.
@ FR_REDIS_COMMAND_TRANSACTION_START
Start of a transaction block.
@ FR_REDIS_COMMAND_NORMAL
A normal, non-transactional command.
@ FR_REDIS_COMMAND_TRANSACTION_END
End of a transaction block.
uint8_t redirected
How many times this command set was redirected.
size_t len
Length of the command string.
trunk_request_t * treq
Trunk request this command set is associated with.
fr_redis_trunk_t * fr_redis_trunk_alloc(fr_redis_cluster_thread_t *cluster_thread, fr_redis_io_conf_t const *io_conf)
Allocate a new trunk.
fr_dlist_head_t pending
Commands yet to be sent.
fr_redis_command_set_t * cmds
Command set this entry belongs to.
static void _redis_pipeline_mux(trunk_connection_t *tconn, connection_t *conn, UNUSED void *uctx)
Enqueue one or more command sets onto a redis handle.
Thread local state for a cluster.
Represents a single command.
Represents a collection of pipelined commands.
Redis asynchronous command pipelining.
void(* fr_redis_command_set_complete_t)(request_t *request, fr_dlist_head_t *completed, void *rctx)
Do something meaningful with the replies to the commands previously issued.
void(* fr_redis_command_set_fail_t)(request_t *request, fr_dlist_head_t *completed, void *rctx)
Write a failure result to the rctx so that the module is aware that the request failed.
fr_redis_pipeline_status_t
@ FR_REDIS_PIPELINE_OK
No failure.
@ FR_REDIS_PIPELINE_BAD_CMDS
Malformed command set.
@ FR_REDIS_PIPELINE_DST_UNAVAILABLE
Cluster or host is down.
@ FR_REDIS_PIPELINE_FAIL
Generic failure.
static void fr_redis_reply_free(redisReply **reply)
Wrap freeReplyObject so we consistently check for NULL pointers.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_aka_sim_id_type_t type
int talloc_link_ctx(TALLOC_CTX *parent, TALLOC_CTX *child)
Link two different parent and child contexts, so the child is freed before the parent.
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
void trunk_request_signal_fail(trunk_request_t *treq)
Signal that a trunk request failed.
trunk_enqueue_t trunk_request_enqueue(trunk_request_t **treq_out, trunk_t *trunk, request_t *request, void *preq, void *rctx)
Enqueue a request that needs data written to the trunk.
int trunk_connection_pop_request(trunk_request_t **treq_out, trunk_connection_t *tconn)
Pop a request off a connection's pending queue.
void trunk_request_signal_sent(trunk_request_t *treq)
Signal that the request was written to a connection successfully.
void trunk_request_signal_complete(trunk_request_t *treq)
Signal that a trunk request is complete.
trunk_t * trunk_alloc(TALLOC_CTX *ctx, fr_event_list_t *el, trunk_io_funcs_t const *funcs, trunk_conf_t const *conf, char const *log_prefix, void const *uctx, bool delay_start)
Allocate a new collection of connections.
Associates request queues with a connection.
Main trunk management handle.
trunk_connection_alloc_t connection_alloc
Allocate a new connection_t.
bool always_writable
Set to true if our ability to write requests to a connection handle is not dependent on the state of ...
trunk_cancel_reason_t
Reasons for a request being cancelled.
@ TRUNK_CANCEL_REASON_NONE
Request has not been cancelled.
@ TRUNK_CANCEL_REASON_SIGNAL
Request cancelled due to a signal.
@ TRUNK_CANCEL_REASON_MOVE
Request cancelled because it's being moved.
@ TRUNK_ENQUEUE_DST_UNAVAILABLE
Destination is down.
@ TRUNK_ENQUEUE_OK
Operation was successful.
@ TRUNK_ENQUEUE_IN_BACKLOG
Request should be enqueued in backlog.
Common configuration parameters for a trunk.
I/O functions to pass to trunk_alloc.
static fr_event_list_t * el