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: 1366368d92eae53c8dfe895d4d73388f3dfe14be $
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: 1366368d92eae53c8dfe895d4d73388f3dfe14be $")
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 request Current request.
76 * @param uctx query context containing query to execute.
77 * @return an unlang_action_t.
78 */
80{
81 fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
82 rlm_sql_t const *inst = query_ctx->inst;
83
84 if (!query_ctx->tconn) {
85 ROPTIONAL(RERROR, ERROR, "Invalid connection");
86 query_ctx->rcode = RLM_SQL_ERROR;
88 }
89
90 /*
91 * We can't implement reconnect logic here, because the caller
92 * may require the original connection to free up queries or
93 * result sets associated with that connection.
94 */
95 (inst->driver->sql_fetch_row)(p_result, request, query_ctx);
96 switch (query_ctx->rcode) {
97 case RLM_SQL_OK:
98 fr_assert(query_ctx->row != NULL);
100
102 fr_assert(query_ctx->row == NULL);
104
105 default:
106 ROPTIONAL(RERROR, ERROR, "Error fetching row");
107 rlm_sql_print_error(inst, request, query_ctx, false);
109 }
110}
111
112/** Retrieve any errors from the SQL driver
113 *
114 * Retrieves errors from the driver from the last operation and writes them to
115 * to request/global log, in the ERROR, WARN, INFO and DEBUG categories.
116 *
117 * @param inst Instance of rlm_sql.
118 * @param request Current request, may be NULL.
119 * @param query_ctx Query context to retrieve errors for.
120 * @param force_debug Force all errors to be logged as debug messages.
121 */
122void rlm_sql_print_error(rlm_sql_t const *inst, request_t *request, fr_sql_query_t *query_ctx, bool force_debug)
123{
124 char const *driver = inst->driver_submodule->name;
125 sql_log_entry_t log[20];
126 size_t num, i;
127 TALLOC_CTX *log_ctx = talloc_new(NULL);
128
129 num = (inst->driver->sql_error)(log_ctx, log, (NUM_ELEMENTS(log)), query_ctx);
130 if (num == 0) {
131 ROPTIONAL(RERROR, ERROR, "Unknown error");
132 talloc_free(log_ctx);
133 return;
134 }
135
136 for (i = 0; i < num; i++) {
137 if (force_debug) goto debug;
138
139 switch (log[i].type) {
140 case L_ERR:
141 ROPTIONAL(RERROR, ERROR, "%s: %s", driver, log[i].msg);
142 break;
143
144 case L_WARN:
145 ROPTIONAL(RWARN, WARN, "%s: %s", driver, log[i].msg);
146 break;
147
148 case L_INFO:
149 ROPTIONAL(RINFO, INFO, "%s: %s", driver, log[i].msg);
150 break;
151
152 case L_DBG:
153 default:
154 debug:
155 ROPTIONAL(RDEBUG2, DEBUG2, "%s: %s", driver, log[i].msg);
156 break;
157 }
158 }
159
160 talloc_free(log_ctx);
161}
162
163/** Automatically run the correct `finish` function when freeing an SQL query
164 *
165 * And mark any associated trunk request as complete.
166 */
168{
169 if (to_free->status > 0) {
170 if (to_free->type == SQL_QUERY_SELECT) {
171 (to_free->inst->driver->sql_finish_select_query)(to_free, &to_free->inst->config);
172 } else {
173 (to_free->inst->driver->sql_finish_query)(to_free, &to_free->inst->config);
174 }
175 }
176 if (to_free->treq) trunk_request_signal_complete(to_free->treq);
177 return 0;
178}
179
180/** Allocate an sql query structure
181 *
182 */
183fr_sql_query_t *fr_sql_query_alloc(TALLOC_CTX *ctx, rlm_sql_t const *inst, request_t *request,
184 trunk_t *trunk, char const *query_str, fr_sql_query_type_t type)
185{
186 fr_sql_query_t *query;
187 MEM(query = talloc(ctx, fr_sql_query_t));
188 *query = (fr_sql_query_t) {
189 .inst = inst,
190 .request = request,
191 .trunk = trunk,
192 .query_str = query_str,
193 .type = type
194 };
195 talloc_set_destructor(query, fr_sql_query_free);
196 return query;
197}
198
199/** Yield processing after submitting a trunk request.
200 */
202 UNUSED request_t *request, UNUSED void *uctx)
203{
204 return UNLANG_ACTION_YIELD;
205}
206
207/** Cancel an SQL query submitted on a trunk
208 */
209static void sql_trunk_query_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
210{
211 fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
212
213 if (!query_ctx->treq) return;
214
215 /*
216 * The query_ctx needs to be parented by the treq so that it still exists
217 * when the cancel_mux callback is run.
218 */
219 if (query_ctx->inst->driver->trunk_io_funcs.request_cancel_mux) talloc_steal(query_ctx->treq, query_ctx);
220
222
223 query_ctx->treq = NULL;
224}
225
226/** Submit an SQL query using a trunk connection.
227 *
228 * @param p_result Result of current module call.
229 * @param request Current request.
230 * @param uctx query context containing query to execute.
231 * @return an unlang_action_t.
232 */
234{
235 fr_sql_query_t *query_ctx = talloc_get_type_abort(uctx, fr_sql_query_t);
236 trunk_enqueue_t status;
237
238 fr_assert(query_ctx->trunk);
239
240 /* There's no query to run, return an error */
241 if (query_ctx->query_str[0] == '\0') {
242 if (request) REDEBUG("Zero length query");
244 }
245
246 /*
247 * If the query already has a treq, and that is not in the "init" state
248 * then this is part of an ongoing transaction and needs requeueing
249 * to submit on the same connection.
250 */
251 if (query_ctx->treq && query_ctx->treq->state != TRUNK_REQUEST_STATE_INIT) {
252 status = trunk_request_requeue(query_ctx->treq);
253 } else {
254 status = trunk_request_enqueue(&query_ctx->treq, query_ctx->trunk, request, query_ctx, NULL);
255 }
256 switch (status) {
257 case TRUNK_ENQUEUE_OK:
259 /*
260 * Drivers such as SQLite which are synchronous run the query immediately
261 * on queueing. If the query fails then the trunk request will be failed
262 * in which case the query_ctx will no longer have a trunk request.
263 */
264 if (!query_ctx->treq) RETURN_UNLANG_FAIL;
265
266 /*
267 * Synchronous drivers will have processed the query and set the
268 * state of the trunk request to reapable - so in that case don't
269 * yield (in sql_trunk_query_start)
270 */
271 if (unlang_function_push_with_result(/* allow the caller of rlm_sql_trunk_query to get at the rcode */p_result,
272 request,
273 query_ctx->treq->state == TRUNK_REQUEST_STATE_REAPABLE ?
275 query_ctx->type == SQL_QUERY_SELECT ?
276 query_ctx->inst->driver->sql_select_query_resume :
277 query_ctx->inst->driver->sql_query_resume,
278 sql_trunk_query_cancel, ~FR_SIGNAL_CANCEL,
279 UNLANG_SUB_FRAME, query_ctx) < 0) RETURN_UNLANG_FAIL;
280 p_result->rcode = RLM_MODULE_OK;
282
283 default:
284 REDEBUG("Unable to enqueue SQL query");
285 query_ctx->status = SQL_QUERY_FAILED;
286 query_ctx->rcode = RLM_SQL_ERROR;
288 }
289}
290
291/** Process the results of an SQL query to produce a map list.
292 *
293 */
295{
296 fr_sql_map_ctx_t *map_ctx = talloc_get_type_abort(uctx, fr_sql_map_ctx_t);
297 tmpl_rules_t lhs_rules = (tmpl_rules_t) {
298 .attr = {
299 .dict_def = request->local_dict,
300 .list_def = map_ctx->list,
301 .list_presence = TMPL_ATTR_LIST_ALLOW
302 }
303 };
304 tmpl_rules_t rhs_rules = lhs_rules;
305 fr_sql_query_t *query_ctx = map_ctx->query_ctx;
306 rlm_sql_row_t row;
307 map_t *parent = NULL;
308 rlm_sql_t const *inst = map_ctx->inst;
309
311
312 if (query_ctx->rcode != RLM_SQL_OK) RETURN_UNLANG_FAIL;
313
314 while ((inst->fetch_row(p_result, request, query_ctx) == UNLANG_ACTION_CALCULATE_RESULT) &&
315 (query_ctx->rcode == RLM_SQL_OK)) {
316 map_t *map;
317
318 row = query_ctx->row;
319 if (!row[2] || !row[3] || !row[4]) {
320 RPERROR("SQL query returned NULL values");
322 }
323 if (map_afrom_fields(map_ctx->ctx, &map, &parent, request, row[2], row[4], row[3],
324 &lhs_rules, &rhs_rules,
325 !(inst->config.expand_rhs || map_ctx->expand_rhs)) < 0) {
326 RPEDEBUG("Data read from SQL cannot be parsed.");
327 REDEBUG(" %s", row[2]);
328 REDEBUG(" %s", row[4]);
329 REDEBUG(" %s", row[3]);
331 }
332 if (!map->parent) map_list_insert_tail(map_ctx->out, map);
333
334 map_ctx->rows++;
335 }
336 talloc_free(query_ctx);
337
339}
340
341/** Submit the query to get any user / group check or reply pairs
342 *
343 */
345{
346 rlm_sql_t const *inst = map_ctx->inst;
347
348 fr_assert(request);
349
350 MEM(map_ctx->query_ctx = fr_sql_query_alloc(map_ctx->ctx, inst, request, trunk,
351 map_ctx->query->vb_strvalue, SQL_QUERY_SELECT));
352
354 request,
355 NULL,
357 NULL, 0,
359 map_ctx) < 0) return UNLANG_ACTION_FAIL;
360
361 return unlang_function_push_with_result(/* discard, sql_get_map_list_resume uses query_ctx->rcode */ NULL,
362 request,
363 inst->select,
364 NULL,
365 NULL, 0,
367 map_ctx->query_ctx);
368}
369
370/*
371 * Log the query to a file.
372 */
373void rlm_sql_query_log(rlm_sql_t const *inst, char const *filename, char const *query)
374{
375 int fd;
376 size_t len;
377 bool failed = false; /* Write the log message outside of the critical region */
378
379 fd = exfile_open(inst->ef, filename, 0640, NULL);
380 if (fd < 0) {
381 ERROR("Couldn't open logfile '%s': %s", filename, fr_syserror(errno));
382
383 /* coverity[missing_unlock] */
384 return;
385 }
386
387 len = strlen(query);
388 if ((write(fd, query, len) < 0) || (write(fd, ";\n", 2) < 0)) failed = true;
389
390 if (failed) ERROR("Failed writing to logfile '%s': %s", filename, fr_syserror(errno));
391
392 exfile_close(inst->ef, fd);
393}
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:41
log_entry msg
Definition acutest.h:794
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
#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:505
int exfile_close(exfile_t *ef, int fd)
Close the log file.
Definition exfile.c:561
#define unlang_function_push_with_result(_result_p, _request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack that produces a result.
Definition function.h:144
#define UNLANG_SUB_FRAME
Definition interpret.h:37
rlm_rcode_t rcode
The current rcode, from executing the instruction or merging the result from a frame.
Definition interpret.h:134
#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, bool bare_word_only)
Convert a fr_pair_t into a map.
Definition map.c:2527
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
#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_UNLANG_INVALID
Definition rcode.h:60
#define RETURN_UNLANG_FAIL
Definition rcode.h:57
#define RETURN_UNLANG_OK
Definition rcode.h:58
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:43
fr_dict_attr_t const * request_attr_request
Definition request.c:43
Prototypes and functions for the SQL module.
fr_sql_query_status_t status
Status of the query.
Definition rlm_sql.h:144
trunk_connection_t * tconn
Trunk connection this query is being run on.
Definition rlm_sql.h:140
fr_sql_query_type_t type
Type of query.
Definition rlm_sql.h:143
trunk_t * trunk
Trunk this query is being run on.
Definition rlm_sql.h:139
rlm_sql_t const * inst
Module instance for this query.
Definition rlm_sql.h:137
char const * query_str
Query string to run.
Definition rlm_sql.h:142
fr_sql_query_t * query_ctx
Query context.
Definition rlm_sql.h:156
map_list_t * out
List to append entries to.
Definition rlm_sql.h:158
@ 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:119
@ SQL_QUERY_SELECT
Definition rlm_sql.h:120
bool expand_rhs
for reply items
Definition rlm_sql.h:160
TALLOC_CTX * ctx
To allocate map entries in.
Definition rlm_sql.h:153
char ** rlm_sql_row_t
Definition rlm_sql.h:59
rlm_sql_t const * inst
Module instance data.
Definition rlm_sql.h:154
int rows
How many rows the query returned.
Definition rlm_sql.h:159
rlm_sql_row_t row
Row data from the last query.
Definition rlm_sql.h:146
sql_rcode_t rcode
Result code.
Definition rlm_sql.h:145
fr_value_box_t * query
Query string used for fetching pairs.
Definition rlm_sql.h:155
trunk_request_t * treq
Trunk request for this query.
Definition rlm_sql.h:141
@ SQL_QUERY_FAILED
Failed to submit.
Definition rlm_sql.h:127
fr_dict_attr_t const * list
Default list for pair evaluation.
Definition rlm_sql.h:157
Context used when fetching attribute value pairs as a map list.
Definition rlm_sql.h:152
Definition rlm_sql.h:61
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:335
@ TMPL_ATTR_LIST_ALLOW
Attribute refs are allowed to have a list.
Definition tmpl.h:262
struct tmpl_rules_s tmpl_rules_t
Definition tmpl.h:233
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
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:183
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:167
unlang_action_t sql_get_map_list(unlang_result_t *p_result, 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:344
unlang_action_t rlm_sql_fetch_row(unlang_result_t *p_result, request_t *request, void *uctx)
Call the driver's sql_fetch_row function.
Definition sql.c:79
void rlm_sql_query_log(rlm_sql_t const *inst, char const *filename, char const *query)
Definition sql.c:373
static unlang_action_t sql_get_map_list_resume(unlang_result_t *p_result, request_t *request, void *uctx)
Process the results of an SQL query to produce a map list.
Definition sql.c:294
fr_table_num_sorted_t const sql_rcode_table[]
Definition sql.c:55
static unlang_action_t sql_trunk_query_start(UNUSED unlang_result_t *p_result, UNUSED request_t *request, UNUSED void *uctx)
Yield processing after submitting a trunk request.
Definition sql.c:201
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:209
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:122
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
unlang_action_t rlm_sql_trunk_query(unlang_result_t *p_result, request_t *request, void *uctx)
Submit an SQL query using a trunk connection.
Definition sql.c:233
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
unlang_function_with_result_t sql_select_query_resume
Callback run after an SQL select trunk query is run.
Definition rlm_sql.h:206
trunk_io_funcs_t trunk_io_funcs
Trunk callback functions for this driver.
Definition rlm_sql.h:224
sql_rcode_t(* sql_finish_query)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
Definition rlm_sql.h:217
sql_rcode_t(* sql_finish_select_query)(fr_sql_query_t *query_ctx, rlm_sql_config_t const *config)
Definition rlm_sql.h:218
unlang_function_with_result_t sql_query_resume
Callback run after an SQL trunk query is run.
Definition rlm_sql.h:205
rlm_sql_config_t config
Definition rlm_sql.h:228
rlm_sql_driver_t const * driver
Driver's exported interface.
Definition rlm_sql.h:235
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
Definition tmpl.h:295
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:273
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:2586
trunk_enqueue_t trunk_request_requeue(trunk_request_t *treq)
Re-enqueue a request on the same connection.
Definition trunk.c:2675
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
Definition trunk.c:2151
void trunk_request_signal_complete(trunk_request_t *treq)
Signal that a trunk request is complete.
Definition trunk.c:2093
Main trunk management handle.
Definition trunk.c:197
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:839