The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
sql.c
Go to the documentation of this file.
1/*
2 * sql.c rlm_sql - FreeRADIUS SQL Module
3 * Main code directly taken from ICRADIUS
4 *
5 * Version: $Id: 0320b71ad6b2a7eab816d4e9431faaad1ffcc995 $
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * @copyright 2001,2006 The FreeRADIUS server project
22 * @copyright 2000 Mike Machado (mike@innercite.com)
23 * @copyright 2000 Alan DeKok (aland@freeradius.org)
24 * @copyright 2001 Chad Miller (cmiller@surfsouth.com)
25 */
26
27RCSID("$Id: 0320b71ad6b2a7eab816d4e9431faaad1ffcc995 $")
28
29#define LOG_PREFIX inst->name
30
31#include <freeradius-devel/server/base.h>
32#include <freeradius-devel/util/debug.h>
33
34#include <sys/file.h>
35#include <sys/stat.h>
36
37#include <ctype.h>
38
39#include "rlm_sql.h"
40
41/*
42 * Translate rlm_sql rcodes to humanly
43 * readable reason strings.
44 */
46 { L("need alt query"), RLM_SQL_ALT_QUERY },
47 { L("no connection"), RLM_SQL_RECONNECT },
48 { L("no more rows"), RLM_SQL_NO_MORE_ROWS },
49 { L("query invalid"), RLM_SQL_QUERY_INVALID },
50 { L("server error"), RLM_SQL_ERROR },
51 { L("success"), RLM_SQL_OK }
52};
54
56 { L("alternate"), RLM_SQL_ALT_QUERY },
57 { L("empty"), RLM_SQL_NO_MORE_ROWS },
58 { L("error"), RLM_SQL_ERROR },
59 { L("invalid"), RLM_SQL_QUERY_INVALID },
60 { L("ok"), RLM_SQL_OK },
61 { L("reconnect"), RLM_SQL_RECONNECT }
62};
64
65/** Call the driver's sql_fetch_row function
66 *
67 * Calls the driver's sql_fetch_row logging any errors. On success, will
68 * write row data to ``uctx->row``.
69 *
70 * The rcode within the query context is updated to
71 * - #RLM_SQL_OK on success.
72 * - other #sql_rcode_t constants on error.
73 *
74 * @param p_result Result of current module call.
75 * @param priority Unused.
76 * @param request Current request.
77 * @param uctx query context containing query to execute.
78 * @return an unlang_action_t.
79 */
80unlang_action_t rlm_sql_fetch_row(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
81{
82 fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
83 rlm_sql_t const *inst = query_ctx->inst;
84
85 if (!query_ctx->tconn) {
86 ROPTIONAL(RERROR, ERROR, "Invalid connection");
87 query_ctx->rcode = RLM_SQL_ERROR;
89 }
90
91 /*
92 * We can't implement reconnect logic here, because the caller
93 * may require the original connection to free up queries or
94 * result sets associated with that connection.
95 */
96 (inst->driver->sql_fetch_row)(p_result, NULL, request, query_ctx);
97 switch (query_ctx->rcode) {
98 case RLM_SQL_OK:
99 fr_assert(query_ctx->row != NULL);
101
103 fr_assert(query_ctx->row == NULL);
105
106 default:
107 ROPTIONAL(RERROR, ERROR, "Error fetching row");
108 rlm_sql_print_error(inst, request, query_ctx, false);
110 }
111}
112
113/** Retrieve any errors from the SQL driver
114 *
115 * Retrieves errors from the driver from the last operation and writes them to
116 * to request/global log, in the ERROR, WARN, INFO and DEBUG categories.
117 *
118 * @param inst Instance of rlm_sql.
119 * @param request Current request, may be NULL.
120 * @param query_ctx Query context to retrieve errors for.
121 * @param force_debug Force all errors to be logged as debug messages.
122 */
123void rlm_sql_print_error(rlm_sql_t const *inst, request_t *request, fr_sql_query_t *query_ctx, bool force_debug)
124{
125 char const *driver = inst->driver_submodule->name;
126 sql_log_entry_t log[20];
127 size_t num, i;
128 TALLOC_CTX *log_ctx = talloc_new(NULL);
129
130 num = (inst->driver->sql_error)(log_ctx, log, (NUM_ELEMENTS(log)), query_ctx);
131 if (num == 0) {
132 ROPTIONAL(RERROR, ERROR, "Unknown error");
133 talloc_free(log_ctx);
134 return;
135 }
136
137 for (i = 0; i < num; i++) {
138 if (force_debug) goto debug;
139
140 switch (log[i].type) {
141 case L_ERR:
142 ROPTIONAL(RERROR, ERROR, "%s: %s", driver, log[i].msg);
143 break;
144
145 case L_WARN:
146 ROPTIONAL(RWARN, WARN, "%s: %s", driver, log[i].msg);
147 break;
148
149 case L_INFO:
150 ROPTIONAL(RINFO, INFO, "%s: %s", driver, log[i].msg);
151 break;
152
153 case L_DBG:
154 default:
155 debug:
156 ROPTIONAL(RDEBUG2, DEBUG2, "%s: %s", driver, log[i].msg);
157 break;
158 }
159 }
160
161 talloc_free(log_ctx);
162}
163
164/** Automatically run the correct `finish` function when freeing an SQL query
165 *
166 * And mark any associated trunk request as complete.
167 */
169{
170 if (to_free->status > 0) {
171 if (to_free->type == SQL_QUERY_SELECT) {
172 (to_free->inst->driver->sql_finish_select_query)(to_free, &to_free->inst->config);
173 } else {
174 (to_free->inst->driver->sql_finish_query)(to_free, &to_free->inst->config);
175 }
176 }
177 if (to_free->treq) trunk_request_signal_complete(to_free->treq);
178 return 0;
179}
180
181/** Allocate an sql query structure
182 *
183 */
184fr_sql_query_t *fr_sql_query_alloc(TALLOC_CTX *ctx, rlm_sql_t const *inst, request_t *request,
185 trunk_t *trunk, char const *query_str, fr_sql_query_type_t type)
186{
187 fr_sql_query_t *query;
188 MEM(query = talloc(ctx, fr_sql_query_t));
189 *query = (fr_sql_query_t) {
190 .inst = inst,
191 .request = request,
192 .trunk = trunk,
193 .query_str = query_str,
194 .type = type
195 };
196 talloc_set_destructor(query, fr_sql_query_free);
197 return query;
198}
199
200/** Yield processing after submitting a trunk request.
201 */
203 UNUSED request_t *request, UNUSED void *uctx)
204{
205 return UNLANG_ACTION_YIELD;
206}
207
208/** Cancel an SQL query submitted on a trunk
209 */
210static void sql_trunk_query_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
211{
212 fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
213
214 if (!query_ctx->treq) return;
215
216 /*
217 * The query_ctx needs to be parented by the treq so that it still exists
218 * when the cancel_mux callback is run.
219 */
220 if (query_ctx->inst->driver->trunk_io_funcs.request_cancel_mux) talloc_steal(query_ctx->treq, query_ctx);
221
223
224 query_ctx->treq = NULL;
225}
226
227/** Submit an SQL query using a trunk connection.
228 *
229 * @param p_result Result of current module call.
230 * @param priority Unused.
231 * @param request Current request.
232 * @param uctx query context containing query to execute.
233 * @return an unlang_action_t.
234 */
235unlang_action_t rlm_sql_trunk_query(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
236{
237 fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
238 trunk_enqueue_t status;
239
240 fr_assert(query_ctx->trunk);
241
242 /* There's no query to run, return an error */
243 if (query_ctx->query_str[0] == '\0') {
244 if (request) REDEBUG("Zero length query");
246 }
247
248 /*
249 * If the query already has a treq, and that is not in the "init" state
250 * then this is part of an ongoing transaction and needs requeueing
251 * to submit on the same connection.
252 */
253 if (query_ctx->treq && query_ctx->treq->state != TRUNK_REQUEST_STATE_INIT) {
254 status = trunk_request_requeue(query_ctx->treq);
255 } else {
256 status = trunk_request_enqueue(&query_ctx->treq, query_ctx->trunk, request, query_ctx, NULL);
257 }
258 switch (status) {
259 case TRUNK_ENQUEUE_OK:
261 /*
262 * Drivers such as SQLite which are synchronous run the query immediately
263 * on queueing. If the query fails then the trunk request will be failed
264 * in which case the query_ctx will no longer have a trunk request.
265 */
266 if (!query_ctx->treq) RETURN_MODULE_FAIL;
267
268 /*
269 * Synchronous drivers will have processed the query and set the
270 * state of the trunk request to reapable - so in that case don't
271 * yield (in sql_trunk_query_start)
272 */
273 if (unlang_function_push(request,
274 query_ctx->treq->state == TRUNK_REQUEST_STATE_REAPABLE ?
276 query_ctx->type == SQL_QUERY_SELECT ?
277 query_ctx->inst->driver->sql_select_query_resume :
278 query_ctx->inst->driver->sql_query_resume,
279 sql_trunk_query_cancel, ~FR_SIGNAL_CANCEL,
280 UNLANG_SUB_FRAME, query_ctx) < 0) RETURN_MODULE_FAIL;
281 *p_result = RLM_MODULE_OK;
283
284 default:
285 REDEBUG("Unable to enqueue SQL query");
286 query_ctx->status = SQL_QUERY_FAILED;
287 query_ctx->rcode = RLM_SQL_ERROR;
289 }
290}
291
292/** Process the results of an SQL query to produce a map list.
293 *
294 */
295static unlang_action_t sql_get_map_list_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
296{
297 fr_sql_map_ctx_t *map_ctx = talloc_get_type_abort(uctx, fr_sql_map_ctx_t);
298 tmpl_rules_t lhs_rules = (tmpl_rules_t) {
299 .attr = {
300 .dict_def = request->dict,
302 .list_def = map_ctx->list,
303 .list_presence = TMPL_ATTR_LIST_ALLOW
304 }
305 };
306 tmpl_rules_t rhs_rules = lhs_rules;
307 fr_sql_query_t *query_ctx = map_ctx->query_ctx;
308 rlm_sql_row_t row;
309 map_t *parent = NULL;
310 rlm_sql_t const *inst = map_ctx->inst;
311
314
315 if (query_ctx->rcode != RLM_SQL_OK) RETURN_MODULE_FAIL;
316
317 while ((inst->fetch_row(p_result, NULL, request, query_ctx) == UNLANG_ACTION_CALCULATE_RESULT) &&
318 (query_ctx->rcode == RLM_SQL_OK)) {
319 map_t *map;
320
321 row = query_ctx->row;
322 if (!row[2] || !row[3] || !row[4]) {
323 RPERROR("SQL query returned NULL values");
325 }
326 if (map_afrom_fields(map_ctx->ctx, &map, &parent, request, row[2], row[4], row[3], &lhs_rules, &rhs_rules) < 0) {
327 RPEDEBUG("Error parsing user data from database result");
329 }
330 if (!map->parent) map_list_insert_tail(map_ctx->out, map);
331
332 map_ctx->rows++;
333 }
334 talloc_free(query_ctx);
335
337}
338
339/** Submit the query to get any user / group check or reply pairs
340 *
341 */
343{
344 rlm_sql_t const *inst = map_ctx->inst;
345
346 fr_assert(request);
347
348 MEM(map_ctx->query_ctx = fr_sql_query_alloc(map_ctx->ctx, inst, request, trunk,
349 map_ctx->query->vb_strvalue, SQL_QUERY_SELECT));
350
351 if (unlang_function_push(request, NULL, sql_get_map_list_resume, NULL, 0, UNLANG_SUB_FRAME, map_ctx) < 0) return UNLANG_ACTION_FAIL;
352
353 return unlang_function_push(request, inst->select, NULL, NULL, 0, UNLANG_SUB_FRAME, map_ctx->query_ctx);
354}
355
356/*
357 * Log the query to a file.
358 */
359void rlm_sql_query_log(rlm_sql_t const *inst, char const *filename, char const *query)
360{
361 int fd;
362 size_t len;
363 bool failed = false; /* Write the log message outside of the critical region */
364
365 fd = exfile_open(inst->ef, filename, 0640, NULL);
366 if (fd < 0) {
367 ERROR("Couldn't open logfile '%s': %s", filename, fr_syserror(errno));
368
369 /* coverity[missing_unlock] */
370 return;
371 }
372
373 len = strlen(query);
374 if ((write(fd, query, len) < 0) || (write(fd, ";\n", 2) < 0)) failed = true;
375
376 if (failed) ERROR("Failed writing to logfile '%s': %s", filename, fr_syserror(errno));
377
378 exfile_close(inst->ef, fd);
379}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
@ UNLANG_ACTION_YIELD
Temporarily pause execution until an event occurs.
Definition action.h:42
log_entry msg
Definition acutest.h:794
#define RCSID(id)
Definition build.h:483
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
int exfile_open(exfile_t *ef, char const *filename, mode_t permissions, off_t *offset)
Open a new log file, or maybe an existing one.
Definition exfile.c:506
int exfile_close(exfile_t *ef, int fd)
Close the log file.
Definition exfile.c:562
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
Definition function.h:111
#define UNLANG_SUB_FRAME
Definition interpret.h:36
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition log.h:528
#define RWARN(fmt,...)
Definition log.h:297
#define RERROR(fmt,...)
Definition log.h:298
#define RPERROR(fmt,...)
Definition log.h:302
#define RINFO(fmt,...)
Definition log.h:296
#define RPEDEBUG(fmt,...)
Definition log.h:376
int map_afrom_fields(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, request_t *request, char const *lhs, char const *op_str, char const *rhs, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules)
Convert a fr_pair_t into a map.
Definition map.c:2439
talloc_free(reap)
@ L_WARN
Warning.
Definition log.h:57
@ L_ERR
Error message.
Definition log.h:56
@ L_INFO
Informational message.
Definition log.h:55
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
@ TMPL_ATTR_REF_PREFIX_AUTO
Attribute refs may have a '&' prefix.
@ TMPL_ATTR_REF_PREFIX_YES
Attribute refs must have '&' prefix.
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define DEBUG2(fmt,...)
Definition radclient.h:43
#define WARN(fmt,...)
Definition radclient.h:47
#define INFO(fmt,...)
Definition radict.c:54
#define RETURN_MODULE_INVALID
Definition rcode.h:59
#define RETURN_MODULE_OK
Definition rcode.h:57
#define RETURN_MODULE_FAIL
Definition rcode.h:56
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:43
fr_dict_attr_t const * request_attr_request
Definition request.c:45
Prototypes and functions for the SQL module.
fr_sql_query_status_t status
Status of the query.
Definition rlm_sql.h:138
trunk_connection_t * tconn
Trunk connection this query is being run on.
Definition rlm_sql.h:134
fr_sql_query_type_t type
Type of query.
Definition rlm_sql.h:137
trunk_t * trunk
Trunk this query is being run on.
Definition rlm_sql.h:133
rlm_sql_t const * inst
Module instance for this query.
Definition rlm_sql.h:131
char const * query_str
Query string to run.
Definition rlm_sql.h:136
fr_sql_query_t * query_ctx
Query context.
Definition rlm_sql.h:150
map_list_t * out
List to append entries to.
Definition rlm_sql.h:152
@ RLM_SQL_QUERY_INVALID
Query syntax error.
Definition rlm_sql.h:45
@ RLM_SQL_ALT_QUERY
Key constraint violation, use an alternative query.
Definition rlm_sql.h:49
@ RLM_SQL_RECONNECT
Stale connection, should reconnect.
Definition rlm_sql.h:48
@ RLM_SQL_ERROR
General connection/server error.
Definition rlm_sql.h:46
@ RLM_SQL_OK
Success.
Definition rlm_sql.h:47
@ RLM_SQL_NO_MORE_ROWS
No more rows available.
Definition rlm_sql.h:50
fr_sql_query_type_t
Definition rlm_sql.h:113
@ SQL_QUERY_SELECT
Definition rlm_sql.h:114
TALLOC_CTX * ctx
To allocate map entries in.
Definition rlm_sql.h:147
char ** rlm_sql_row_t
Definition rlm_sql.h:59
rlm_sql_t const * inst
Module instance data.
Definition rlm_sql.h:148
int rows
How many rows the query returned.
Definition rlm_sql.h:153
rlm_sql_row_t row
Row data from the last query.
Definition rlm_sql.h:140
sql_rcode_t rcode
Result code.
Definition rlm_sql.h:139
fr_value_box_t * query
Query string used for fetching pairs.
Definition rlm_sql.h:149
trunk_request_t * treq
Trunk request for this query.
Definition rlm_sql.h:135
@ SQL_QUERY_FAILED
Failed to submit.
Definition rlm_sql.h:121
fr_dict_attr_t const * list
Default list for pair evaluation.
Definition rlm_sql.h:151
Context used when fetching attribute value pairs as a map list.
Definition rlm_sql.h:146
Definition rlm_sql.h:61
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:344
@ TMPL_ATTR_LIST_ALLOW
Attribute refs are allowed to have a list.
Definition tmpl.h:274
struct tmpl_rules_s tmpl_rules_t
Definition tmpl.h:236
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:341
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
fr_sql_query_t * fr_sql_query_alloc(TALLOC_CTX *ctx, rlm_sql_t const *inst, request_t *request, trunk_t *trunk, char const *query_str, fr_sql_query_type_t type)
Allocate an sql query structure.
Definition sql.c:184
size_t sql_rcode_table_len
Definition sql.c:63
static int fr_sql_query_free(fr_sql_query_t *to_free)
Automatically run the correct finish function when freeing an SQL query.
Definition sql.c:168
unlang_action_t rlm_sql_fetch_row(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Call the driver's sql_fetch_row function.
Definition sql.c:80
void rlm_sql_query_log(rlm_sql_t const *inst, char const *filename, char const *query)
Definition sql.c:359
fr_table_num_sorted_t const sql_rcode_table[]
Definition sql.c:55
unlang_action_t sql_get_map_list(request_t *request, fr_sql_map_ctx_t *map_ctx, trunk_t *trunk)
Submit the query to get any user / group check or reply pairs.
Definition sql.c:342
unlang_action_t rlm_sql_trunk_query(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Submit an SQL query using a trunk connection.
Definition sql.c:235
static void sql_trunk_query_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
Cancel an SQL query submitted on a trunk.
Definition sql.c:210
static unlang_action_t sql_trunk_query_start(UNUSED rlm_rcode_t *p_result, UNUSED int *priority, UNUSED request_t *request, UNUSED void *uctx)
Yield processing after submitting a trunk request.
Definition sql.c:202
static unlang_action_t sql_get_map_list_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Process the results of an SQL query to produce a map list.
Definition sql.c:295
void rlm_sql_print_error(rlm_sql_t const *inst, request_t *request, fr_sql_query_t *query_ctx, bool force_debug)
Retrieve any errors from the SQL driver.
Definition sql.c:123
size_t sql_rcode_description_table_len
Definition sql.c:53
fr_table_num_sorted_t const sql_rcode_description_table[]
Definition sql.c:45
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
Value pair map.
Definition map.h:77
map_t * parent
Definition map.h:88
trunk_io_funcs_t trunk_io_funcs
Trunk callback functions for this driver.
Definition rlm_sql.h:217
unlang_function_t sql_query_resume
Callback run after an SQL trunk query is run.
Definition rlm_sql.h:198
sql_rcode_t(* sql_finish_query)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
Definition rlm_sql.h:210
sql_rcode_t(* sql_finish_select_query)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
Definition rlm_sql.h:211
unlang_function_t sql_select_query_resume
Callback run after an SQL select trunk query is run.
Definition rlm_sql.h:199
rlm_sql_config_t config
Definition rlm_sql.h:221
rlm_sql_driver_t const * driver
Driver's exported interface.
Definition rlm_sql.h:228
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
Definition tmpl.h:307
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:285
tmpl_attr_prefix_t prefix
Whether the attribute reference requires a prefix.
Definition tmpl.h:310
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
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.
Definition trunk.c:2587
trunk_enqueue_t trunk_request_requeue(trunk_request_t *treq)
Re-enqueue a request on the same connection.
Definition trunk.c:2676
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
Definition trunk.c:2152
void trunk_request_signal_complete(trunk_request_t *treq)
Signal that a trunk request is complete.
Definition trunk.c:2094
Main trunk management handle.
Definition trunk.c:198
trunk_enqueue_t
Definition trunk.h:148
@ TRUNK_ENQUEUE_OK
Operation was successful.
Definition trunk.h:150
@ TRUNK_ENQUEUE_IN_BACKLOG
Request should be enqueued in backlog.
Definition trunk.h:149
trunk_request_cancel_mux_t request_cancel_mux
!< Read one or more requests from a connection.
Definition trunk.h:746
@ TRUNK_REQUEST_STATE_REAPABLE
Request has been written, needs to persist, but we are not currently waiting for any response.
Definition trunk.h:173
@ TRUNK_REQUEST_STATE_INIT
Initial state.
Definition trunk.h:162
static fr_slen_t parent
Definition pair.h:851