The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
request.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
5 * (at 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: 6d0a283701e1c804cb11c364277b8d74e1468f7d $
19 *
20 * @brief Functions for allocating requests and storing internal data in them.
21 * @file src/lib/server/request.c
22 *
23 * @copyright 2015 The FreeRADIUS server project
24 */
25RCSID("$Id: 6d0a283701e1c804cb11c364277b8d74e1468f7d $")
26
27#include <freeradius-devel/server/request.h>
28#include <freeradius-devel/server/request_data.h>
29#include <freeradius-devel/unlang/interpret.h>
30
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/util/atexit.h>
33
35
38 { .out = &dict_freeradius, .proto = "freeradius" },
39 { NULL }
40};
41
48
51 { .out = &request_attr_root, .name = "root", .type = FR_TYPE_GROUP, .dict = &dict_freeradius },
52 { .out = &request_attr_request, .name = "request", .type = FR_TYPE_GROUP, .dict = &dict_freeradius },
53 { .out = &request_attr_reply, .name = "reply", .type = FR_TYPE_GROUP, .dict = &dict_freeradius },
54 { .out = &request_attr_control, .name = "control", .type = FR_TYPE_GROUP, .dict = &dict_freeradius },
55 { .out = &request_attr_state, .name = "session-state", .type = FR_TYPE_GROUP, .dict = &dict_freeradius },
56 { .out = &request_attr_local, .name = "local-variables", .type = FR_TYPE_GROUP, .dict = &dict_freeradius },
57 { NULL }
58};
59
60#ifndef NDEBUG
61static int _state_ctx_free(fr_pair_t *state)
62{
63 DEBUG4("state-ctx %p freed", state);
64
65 return 0;
66}
67#endif
68
69static inline void CC_HINT(always_inline) request_log_init_orphan(request_t *request)
70{
71 /*
72 * These may be changed later by request_pre_handler
73 */
74 request->log.lvl = fr_debug_lvl; /* Default to global debug level */
75 if (!request->log.dst) {
76 request->log.dst = talloc_zero(request, log_dst_t);
77 } else {
78 memset(request->log.dst, 0, sizeof(*request->log.dst));
79 }
80 request->log.dst->func = vlog_request;
81 request->log.dst->uctx = &default_log;
82 request->log.dst->lvl = fr_debug_lvl;
83}
84
85/** Prepend another logging destination to the list.
86 *
87
88 * @param request the request
89 * @param log_dst the logging destination
90 * @param lvl the new request debug lvl
91 */
93{
94 log_dst_t *dst;
95
96 if (lvl == L_DBG_LVL_DISABLE) {
97 while (request->log.dst) {
98 dst = request->log.dst->next;
99 talloc_free(request->log.dst);
100 request->log.dst = dst;
101 }
102 request->log.lvl = L_DBG_LVL_OFF;
103 return;
104 }
105
106 /*
107 * Remove a particular log destination.
108 */
109 if (lvl == L_DBG_LVL_OFF) {
110 log_dst_t **last;
111
112 last = &request->log.dst;
113 while (*last) {
114 dst = *last;
115 if (((fr_log_t *)dst->uctx)->parent == log_dst) {
116 *last = dst->next;
117 talloc_free(dst);
118 if (!request->log.dst) request->log.lvl = L_DBG_LVL_OFF;
119 return;
120 }
121
122 last = &(dst->next);
123 }
124
125 return;
126 }
127
128 /*
129 * Change the debug level of an existing destination.
130 */
131 for (dst = request->log.dst; dst != NULL; dst = dst->next) {
132 if (((fr_log_t *)dst->uctx)->parent == log_dst) {
133 dst->lvl = lvl;
134 if (lvl > request->log.lvl) request->log.lvl = lvl;
135 return;
136 }
137 }
138
139 /*
140 * Not found, add a new log destination.
141 */
142 MEM(dst = talloc_zero(request, log_dst_t));
143
144 dst->func = vlog_request;
145 dst->uctx = log_dst;
146
147 dst->lvl = lvl;
148 if (lvl > request->log.lvl) request->log.lvl = lvl;
149 dst->next = request->log.dst;
150
151 request->log.dst = dst;
152}
153
154static inline void CC_HINT(always_inline) request_log_init_child(request_t *child, request_t const *parent)
155{
156 /*
157 * Copy debug information.
158 */
159 memcpy(&(child->log), &(parent->log), sizeof(child->log));
160 child->log.indent.unlang = 0; /* Apart from the indent which we reset */
161 child->log.indent.module = 0; /* Apart from the indent which we reset */
162 child->log.lvl = parent->log.lvl;
163}
164
165static inline void CC_HINT(always_inline) request_log_init_detachable(request_t *child, request_t const *parent)
166{
168
169 /*
170 * Ensure that we use our own version of the logging
171 * information, and not the original request one.
172 */
173 child->log.dst = talloc_zero(child, log_dst_t);
174 memcpy(child->log.dst, parent->log.dst, sizeof(*child->log.dst));
175}
176
177static inline CC_HINT(always_inline) int request_detachable_init(request_t *child, request_t *parent)
178{
179 /*
180 * Associate the child with the parent, using the child's
181 * pointer as a unique identifier. Free it if the parent
182 * goes away, but don't persist it across
183 * challenge-response boundaries.
184 */
185 if (request_data_talloc_add(parent, child, 0, request_t, child, true, true, false) < 0) return -1;
186
187 return 0;
188}
189
190static inline CC_HINT(always_inline) int request_child_init(request_t *child, request_t *parent)
191{
192 child->number = parent->child_number++;
193 if (!child->proto_dict) {
194 child->proto_dict = parent->proto_dict;
195 child->local_dict = parent->proto_dict;
196 }
197
198 if ((parent->seq_start == 0) || (parent->number == parent->seq_start)) {
199 child->name = talloc_typed_asprintf(child, "%s.%" PRIu64, parent->name, child->number);
200 } else {
201 child->name = talloc_typed_asprintf(child, "(%s,%" PRIu64 ").%" PRIu64,
202 parent->name, parent->seq_start, child->number);
203 }
204 child->seq_start = 0; /* children always start with their own sequence */
205 child->parent = parent;
206
207 /*
208 * For new server support.
209 *
210 * FIXME: Key instead off of a "virtual server" data structure.
211 *
212 * FIXME: Permit different servers for inner && outer sessions?
213 */
214 child->packet = fr_packet_alloc(child, true);
215 if (!child->packet) {
216 talloc_free(child);
217 return -1;
218 }
219
220 child->reply = fr_packet_alloc(child, false);
221 if (!child->reply) {
222 talloc_free(child);
223 return -1;
224 }
225
226 return 0;
227}
228
229/** Setup logging and other fields for a request
230 *
231 * @param[in] file the request was allocated in.
232 * @param[in] line the request was allocated on.
233 * @param[in] request to (re)-initialise.
234 * @param[in] type of request to initialise.
235 * @param[in] args Other optional arguments.
236 */
237int _request_init(char const *file, int line,
238 request_t *request, request_type_t type,
240{
241 fr_dict_t const *dict;
242
243 /*
244 * Sanity checks for different requests types
245 */
246 switch (type) {
249
250 if (!fr_cond_assert_msg(!args->parent, "External requests must NOT have a parent")) return -1;
251
252 fr_assert(args->namespace);
253
254 dict = args->namespace;
255 break;
256
258 if (!args || !args->namespace) {
259 dict = fr_dict_internal();
260 } else {
261 dict = args->namespace;
262 }
263 break;
264
266 fr_assert_fail("Detached requests should start as type == REQUEST_TYPE_INTERNAL, "
267 "args->detachable and be detached later");
268 return -1;
269
270 /* Quiet GCC */
271 default:
272 fr_assert_fail("Invalid request type");
273 return -1;
274 }
275
276 *request = (request_t){
277#ifndef NDEBUG
278 .magic = REQUEST_MAGIC,
279#endif
280 .type = type,
281 .master_state = REQUEST_ACTIVE,
282 .proto_dict = fr_dict_proto_dict(dict),
283 .local_dict = dict,
284 .component = "<pre-core>",
285 .flags = {
286 .detachable = args && args->detachable,
287 },
288 .alloc_file = file,
289 .alloc_line = line
290 };
291
292
293 /*
294 * Initialise the stack
295 */
296 MEM(request->stack = unlang_interpret_stack_alloc(request));
297
298 /*
299 * Initialise the request data list
300 */
301 request_data_list_init(&request->data);
302
303 {
304 fr_pair_t *vp = NULL, *pair_root;
305
306 /*
307 * Alloc the pair root this is a
308 * special pair which does not
309 * free its children when it is
310 * freed.
311 */
312 pair_root = fr_pair_root_afrom_da(request, request_attr_root);
313 if (unlikely(!pair_root)) return -1;
314 request->pair_root = pair_root;
315
316 /*
317 * Copy all the pair lists over into
318 * the request. We then check for
319 * the any uninitialised lists and
320 * create them locally.
321 */
322 if (args) memcpy(&request->pair_list, &args->pair_list, sizeof(request->pair_list));
323
324#define list_init(_ctx, _list) \
325 do { \
326 vp = fr_pair_afrom_da(_ctx, request_attr_##_list); \
327 if (unlikely(!vp)) { \
328 talloc_free(pair_root); \
329 memset(&request->pair_list, 0, sizeof(request->pair_list)); \
330 return -1; \
331 } \
332 fr_pair_append(&pair_root->children, vp); \
333 request->pair_list._list = vp; \
334 } while(0)
335
336 if (!request->pair_list.request) list_init(request->pair_root, request);
337 if (!request->pair_list.reply) list_init(request->pair_root, reply);
338 if (!request->pair_list.control) list_init(request->pair_root, control);
339 if (!request->pair_list.local) list_init(request->pair_root, local);
340 if (!request->pair_list.state) {
341 list_init(NULL, state);
342#ifndef NDEBUG
343 talloc_set_destructor(request->pair_list.state, _state_ctx_free);
344#endif
345 }
346 }
347
348 /*
349 * Initialise packets and additional
350 * fields if this is going to be a
351 * child request.
352 */
353 if (args && args->parent) {
354 if (request_child_init(request, args->parent) < 0) return -1;
355
356 if (args->detachable) {
357 if (request_detachable_init(request, args->parent) < 0) return -1;
358 request_log_init_detachable(request, args->parent);
359 } else {
360 request_log_init_child(request, args->parent);
361 }
362 } else {
364 }
365
366 /*
367 * This is only used by src/lib/io/worker.c
368 */
369 fr_dlist_entry_init(&request->listen_entry);
370
371 return 0;
372}
373
374/** Callback for slabs to deinitialise the request
375 *
376 * Does not need to be called for local requests.
377 *
378 * @param[in] request deinitialise
379 * @return
380 * - 0 in the request was deinitialised.
381 * - -1 if the request is in an unexpected state.
382 */
384{
385 fr_assert_msg(!fr_timer_armed(request->timeout),
386 "alloced %s:%i: %s still in the timeout sublist",
387 request->alloc_file,
388 request->alloc_line,
389 request->name ? request->name : "(null)");
390 fr_assert_msg(!fr_heap_entry_inserted(request->runnable),
391 "alloced %s:%i: %s still in the runnable heap ID %i",
392 request->alloc_file,
393 request->alloc_line,
394 request->name ? request->name : "(null)", request->runnable);
395
396 RDEBUG3("Request deinitialising (%p)", request);
397
398 /*
399 * state_ctx is parented separately.
400 */
401 if (request->session_state_ctx) TALLOC_FREE(request->session_state_ctx);
402
403 /*
404 * Zero out everything.
405 */
406 memset(request, 0, sizeof(*request));
407
408#ifndef NDEBUG
409 request->component = "free_list";
410 request->runnable = FR_HEAP_INDEX_INVALID;
411 request->magic = 0x01020304; /* set the request to be nonsense */
412#endif
413
414 return 0;
415}
416
417static inline CC_HINT(always_inline) request_t *request_alloc_pool(TALLOC_CTX *ctx)
418{
419 request_t *request;
420
421 /*
422 * Only allocate requests in the NULL
423 * ctx. There's no scenario where it's
424 * appropriate to allocate them in a
425 * pool, and using a strict talloc
426 * hierarchy means that child requests
427 * cannot be returned to a free list
428 * and would have to be freed.
429 */
430 MEM(request = talloc_pooled_object(ctx, request_t,
433 fr_assert(ctx != request);
434
435 return request;
436}
437
438static int _request_local_free(request_t *request)
439{
440 RDEBUG4("Local request freed (%p)", request);
441
442 /*
443 * Ensure anything that might reference the request is
444 * freed before it is.
445 */
446 talloc_free_children(request);
447
448 /*
449 * state_ctx is parented separately.
450 *
451 * The reason why it's OK to do this, is if the state attributes
452 * need to persist across requests, they will already have been
453 * moved to a fr_state_entry_t, with the state pointers in the
454 * request being set to NULL, before the request is freed/
455 *
456 * Note also that we do NOT call TALLOC_FREE(), which
457 * sets state_ctx=NULL. We don't control the order in
458 * which talloc frees the children. And the parents
459 * state_ctx pointer needs to stick around so that all of
460 * the children can check it.
461 *
462 * If this assertion hits, it means that someone didn't
463 * call fr_state_store_in_parent()
464 */
465 if (request->session_state_ctx) {
466 fr_assert(!request->parent || (request->session_state_ctx != request->parent->session_state_ctx));
467
468 talloc_free(request->session_state_ctx);
469 }
470
471#ifndef NDEBUG
472 request->magic = 0x01020304; /* set the request to be nonsense */
473#endif
474
475 return 0;
476}
477
478/** Allocate a request that's not in the free list
479 *
480 * This can be useful if modules need a persistent request for their own purposes
481 * which needs to be outside of the normal free list, so that it can be freed
482 * when the module requires, not when the thread destructor runs.
483 */
484request_t *_request_local_alloc(char const *file, int line, TALLOC_CTX *ctx,
486{
487 request_t *request;
488
489 request = request_alloc_pool(ctx);
490 if (_request_init(file, line, request, type, args) < 0) return NULL;
491
492 talloc_set_destructor(request, _request_local_free);
493
494 return request;
495}
496
497/** Replace the session_state_ctx with a new one.
498 *
499 * NOTHING should rewrite request->session_state_ctx.
500 *
501 * It's now a pair, and is stored in request->pair_root.
502 * So it's wrong for anyone other than this function to play games with it.
503 *
504 * @param[in] request to replace the state of.
505 * @param[in] new_state state to assign to the request.
506 * May be NULL in which case a new_state state will
507 * be alloced and assigned.
508 *
509 * @return the fr_pair_t containing the old state list.
510 */
512{
513 fr_pair_t *old = request->session_state_ctx;
514
515 fr_assert(request->session_state_ctx != NULL);
516 fr_assert(request->session_state_ctx != new_state);
517
518 fr_pair_remove(&request->pair_root->children, old);
519
520 /*
521 * Save (or delete) the existing state, and re-initialize
522 * it with a brand new one.
523 */
524 if (!new_state) MEM(new_state = fr_pair_afrom_da(NULL, request_attr_state));
525
526 request->session_state_ctx = new_state;
527
528 fr_pair_append(&request->pair_root->children, new_state);
529
530 return old;
531}
532
533/** Unlink a subrequest from its parent
534 *
535 * @note This should be used for requests in preparation for freeing them.
536 *
537 * @param[in] child request to unlink.
538 * @return
539 * - 0 on success.
540 * - -1 on failure.
541 */
543{
544 request_t *request = child->parent;
545
546 /*
547 * Already detached or not detachable
548 */
549 if (request_is_detached(child)) return 0;
550
551 if (!request_is_detachable(child)) {
552 fr_strerror_const("Request is not detachable");
553 return -1;
554 }
555
556 /*
557 * Unlink the child from the parent.
558 */
559 request_data_get(request, child, 0);
560
561 child->parent = NULL;
562
563 /*
564 * Request is now detached
565 */
566 child->type = REQUEST_TYPE_DETACHED;
567
568 /*
569 * ...and is no longer detachable.
570 */
571 child->flags.detachable = 0;
572
573 return 0;
574}
575
576static int _request_global_free(UNUSED void *uctx)
577{
579 return 0;
580}
581
582static int _request_global_init(UNUSED void *uctx)
583{
585 PERROR("%s", __FUNCTION__);
586 return -1;
587 }
589 PERROR("%s", __FUNCTION__);
591 return -1;
592 }
593 return 0;
594}
595
597{
598 int ret;
599 fr_atexit_global_once_ret(&ret, _request_global_init, _request_global_free, NULL);
600 return ret;
601}
602
603#ifdef WITH_VERIFY_PTR
604/*
605 * Verify a packet.
606 */
607static void packet_verify(char const *file, int line,
608 request_t const *request, fr_packet_t const *packet, fr_pair_list_t *list, char const *type)
609{
610 TALLOC_CTX *parent;
611
612 fr_fatal_assert_msg(packet, "CONSISTENCY CHECK FAILED %s[%i]: fr_packet_t %s pointer was NULL",
613 file, line, type);
614
615 parent = talloc_parent(packet);
616 if (parent != request) {
617 fr_log_talloc_report(packet);
619
620
621 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%i]: Expected fr_packet_t %s to be parented "
622 "by %p (%s), but parented by %p (%s)",
623 file, line, type, request, talloc_get_name(request),
624 parent, parent ? talloc_get_name(parent) : "NULL");
625 }
626
627 /*
628 * Enforce nesting at the top level. This catches minor programming bugs in the server core.
629 *
630 * If we care more, we could do these checks recursively. But the tmpl_tokenize code already
631 * enforces parent / child namespaces. So the end user shouldn't be able to break the parenting.
632 *
633 * This code really only checks for programming bugs where the C code creates a pair, and then
634 * adds it to the wrong list. This was happening during the transition from flat to nested, as
635 * the code was in the middle of being fixed. It should only happen now if the programmer
636 * forgets, and uses the wrong APIs.
637 */
638 fr_pair_list_foreach(list, vp) {
639 if (vp->da->flags.is_raw) continue;
640
641 if (vp->da->flags.internal) continue;
642
643 if (vp->da->depth > 1) {
644 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%i]: Expected fr_pair_t %s to be parented "
645 "by (%s), but it is instead at the top-level %s list",
646 file, line, vp->da->name, vp->da->parent->name, type);
647 }
648 }
649
650 PACKET_VERIFY(packet);
651}
652
653/*
654 * Catch horrible talloc errors.
655 */
656void request_verify(char const *file, int line, request_t const *request)
657{
658 request_data_t *rd = NULL;
659
660 fr_fatal_assert_msg(request, "CONSISTENCY CHECK FAILED %s[%i]: request_t pointer was NULL", file, line);
661
662 (void) talloc_get_type_abort_const(request, request_t);
663
664 fr_assert(request->magic == REQUEST_MAGIC);
665
666 (void)talloc_get_type_abort(request->request_ctx, fr_pair_t);
667 fr_pair_list_verify(file, line, request->request_ctx, &request->request_pairs);
668 (void)talloc_get_type_abort(request->reply_ctx, fr_pair_t);
669 fr_pair_list_verify(file, line, request->reply_ctx, &request->reply_pairs);
670 (void)talloc_get_type_abort(request->control_ctx, fr_pair_t);
671 fr_pair_list_verify(file, line, request->control_ctx, &request->control_pairs);
672 (void)talloc_get_type_abort(request->session_state_ctx, fr_pair_t);
673
674#ifndef NDEBUG
675 {
676 TALLOC_CTX *parent = talloc_parent(request->session_state_ctx);
677
678 fr_assert_msg((parent == NULL) || (parent == talloc_null_ctx()),
679 "session_state_ctx must not be parented by another chunk, but is parented by %s",
680 talloc_get_name(talloc_parent(request->session_state_ctx)));
681 }
682#endif
683
684 fr_pair_list_verify(file, line, request->session_state_ctx, &request->session_state_pairs);
685 fr_pair_list_verify(file, line, request->local_ctx, &request->local_pairs);
686
687 fr_assert(request->proto_dict != NULL);
688 fr_assert(request->local_dict != NULL);
689
690 if (request->packet) {
691 packet_verify(file, line, request, request->packet, &request->request_pairs, "request");
692 }
693 if (request->reply) {
694 packet_verify(file, line, request, request->reply, &request->reply_pairs, "reply");
695 }
696
697 if (request->async) {
698 (void) talloc_get_type_abort(request->async, fr_async_t);
699 fr_assert(talloc_parent(request->async) == request);
700 }
701
702 while ((rd = fr_dlist_next(&request->data, rd))) {
703 (void) talloc_get_type_abort(rd, request_data_t);
704
705 if (request_data_persistable(rd)) {
706 fr_assert(request->session_state_ctx);
707 fr_assert(talloc_parent(rd) == request->session_state_ctx);
708 } else {
709 fr_assert(talloc_parent(rd) == request);
710 }
711 }
712}
713#endif
int const char * file
Definition acutest.h:702
va_list args
Definition acutest.h:770
int const char int line
Definition acutest.h:702
void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request)
#define RCSID(id)
Definition build.h:485
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
int fr_log_talloc_report(TALLOC_CTX const *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
Definition debug.c:1147
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:191
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:210
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:216
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:156
#define fr_fatal_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:184
#define MEM(x)
Definition debug.h:36
#define fr_dict_autofree(_to_free)
Definition dict.h:869
fr_dict_t const * fr_dict_proto_dict(fr_dict_t const *dict)
Definition dict_util.c:5016
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:273
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:286
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4134
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4654
#define fr_dict_autoload(_to_load)
Definition dict.h:866
Specifies an attribute which must be present for the module to function.
Definition dict.h:272
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:285
static void fr_dlist_entry_init(fr_dlist_t *entry)
Initialise a linked list without metadata.
Definition dlist.h:138
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition dlist.h:555
static bool fr_heap_entry_inserted(fr_heap_index_t heap_idx)
Check if an entry is inserted into a heap.
Definition heap.h:124
#define FR_HEAP_INDEX_INVALID
Definition heap.h:83
void * unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
Allocate a new unlang stack.
Definition interpret.c:980
Minimal data structure to use the new code.
Definition listen.h:59
void vlog_request(fr_log_type_t type, fr_log_lvl_t lvl, request_t *request, char const *file, int line, char const *fmt, va_list ap, void *uctx)
Send a log message to its destination, possibly including fields from the request.
Definition log.c:293
#define PERROR(_fmt,...)
Definition log.h:228
fr_log_lvl_t lvl
Log messages with lvl >= to this should be logged.
Definition log.h:73
#define RDEBUG3(fmt,...)
Definition log.h:343
#define DEBUG4(_fmt,...)
Definition log.h:267
void * uctx
Context to pass to the logging function.
Definition log.h:72
log_dst_t * next
Next logging destination.
Definition log.h:74
#define RDEBUG4(fmt,...)
Definition log.h:344
log_func_t func
Function to call to log to this destination.
Definition log.h:71
Definition log.h:70
talloc_free(reap)
int fr_debug_lvl
Definition log.c:40
fr_log_t default_log
Definition log.c:292
fr_log_lvl_t
Definition log.h:67
@ L_DBG_LVL_DISABLE
Don't print messages.
Definition log.h:68
@ L_DBG_LVL_OFF
No debug messages.
Definition log.h:69
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition packet.c:38
@ FR_TYPE_GROUP
A grouping of other attributes.
fr_pair_t * fr_pair_root_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
A special allocation function which disables child autofree.
Definition pair.c:247
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1342
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:287
#define fr_assert(_expr)
Definition rad_assert.h:38
static int request_child_init(request_t *child, request_t *parent)
Definition request.c:190
fr_dict_attr_t const * request_attr_request
Definition request.c:43
static int _request_global_init(UNUSED void *uctx)
Definition request.c:582
static void request_log_init_orphan(request_t *request)
Definition request.c:69
static int _request_local_free(request_t *request)
Definition request.c:438
static request_t * request_alloc_pool(TALLOC_CTX *ctx)
Definition request.c:417
#define list_init(_ctx, _list)
int request_slab_deinit(request_t *request)
Callback for slabs to deinitialise the request.
Definition request.c:383
fr_dict_autoload_t request_dict[]
Definition request.c:37
request_t * _request_local_alloc(char const *file, int line, TALLOC_CTX *ctx, request_type_t type, request_init_args_t const *args)
Allocate a request that's not in the free list.
Definition request.c:484
static fr_dict_t const * dict_freeradius
Definition request.c:34
fr_pair_t * request_state_replace(request_t *request, fr_pair_t *new_state)
Replace the session_state_ctx with a new one.
Definition request.c:511
fr_dict_attr_t const * request_attr_control
Definition request.c:45
static int request_detachable_init(request_t *child, request_t *parent)
Definition request.c:177
fr_dict_attr_t const * request_attr_local
Definition request.c:47
fr_dict_attr_t const * request_attr_state
Definition request.c:46
fr_dict_attr_t const * request_attr_reply
Definition request.c:44
fr_dict_attr_autoload_t request_dict_attr[]
Definition request.c:50
void request_log_prepend(request_t *request, fr_log_t *log_dst, fr_log_lvl_t lvl)
Prepend another logging destination to the list.
Definition request.c:92
int request_global_init(void)
Definition request.c:596
int request_detach(request_t *child)
Unlink a subrequest from its parent.
Definition request.c:542
static int _state_ctx_free(fr_pair_t *state)
Definition request.c:61
fr_dict_attr_t const * request_attr_root
Definition request.c:42
int _request_init(char const *file, int line, request_t *request, request_type_t type, request_init_args_t const *args)
Setup logging and other fields for a request.
Definition request.c:237
static void request_log_init_child(request_t *child, request_t const *parent)
Definition request.c:154
static void request_log_init_detachable(request_t *child, request_t const *parent)
Definition request.c:165
static int _request_global_free(UNUSED void *uctx)
Definition request.c:576
#define request_is_detached(_x)
Definition request.h:186
#define REQUEST_MAGIC
Definition request.h:57
#define REQUEST_POOL_HEADERS
Definition request.h:66
request_type_t
Definition request.h:177
@ REQUEST_TYPE_EXTERNAL
A request received on the wire.
Definition request.h:178
@ REQUEST_TYPE_INTERNAL
A request generated internally.
Definition request.h:179
@ REQUEST_TYPE_DETACHED
A request that was generated internally, but is now detached (not associated with a parent request....
Definition request.h:180
#define request_is_detachable(_x)
Definition request.h:187
#define REQUEST_POOL_SIZE
Definition request.h:79
@ REQUEST_ACTIVE
Request is active (running or runnable)
Definition request.h:87
Optional arguments for initialising requests.
Definition request.h:283
void request_data_list_init(fr_dlist_head_t *data)
void * request_data_get(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request.
Per-request opaque data, added by modules.
#define request_data_talloc_add(_request, _unique_ptr, _unique_int, _type, _opaque, _free_on_replace, _free_on_parent, _persist)
Add opaque data to a request_t.
fr_aka_sim_id_type_t type
fr_pair_t * vp
Definition log.h:96
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:514
void * talloc_null_ctx(void)
Retrieve the current talloc NULL ctx.
Definition talloc.c:49
#define talloc_get_type_abort_const
Definition talloc.h:287
#define talloc_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:180
static bool fr_timer_armed(fr_timer_t *ev)
Definition timer.h:120
#define PACKET_VERIFY(_x)
Definition packet.h:42
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
Definition pair_inline.c:93
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition pair.h:261
static fr_slen_t parent
Definition pair.h:839
#define fr_strerror_const(_msg)
Definition strerror.h:223