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: 6fd2371ef81178908769a6d15a4a273cc8ec5291 $
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: 6fd2371ef81178908769a6d15a4a273cc8ec5291 $")
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/** The thread local free list
61 *
62 * Any entries remaining in the list will be freed when the thread is joined
63 */
64static _Thread_local fr_dlist_head_t *request_free_list; /* macro */
65
66#ifndef NDEBUG
67static int _state_ctx_free(fr_pair_t *state)
68{
69 DEBUG4("state-ctx %p freed", state);
70
71 return 0;
72}
73#endif
74
75static inline void CC_HINT(always_inline) request_log_init_orphan(request_t *request)
76{
77 /*
78 * These may be changed later by request_pre_handler
79 */
80 request->log.lvl = fr_debug_lvl; /* Default to global debug level */
81 if (!request->log.dst) {
82 request->log.dst = talloc_zero(request, log_dst_t);
83 } else {
84 memset(request->log.dst, 0, sizeof(*request->log.dst));
85 }
86 request->log.dst->func = vlog_request;
87 request->log.dst->uctx = &default_log;
88 request->log.dst->lvl = fr_debug_lvl;
89}
90
91/** Prepend another logging destination to the list.
92 *
93
94 * @param request the request
95 * @param log_dst the logging destination
96 * @param lvl the new request debug lvl
97 */
99{
100 log_dst_t *dst;
101
102 if (lvl == L_DBG_LVL_DISABLE) {
103 while (request->log.dst) {
104 dst = request->log.dst->next;
105 talloc_free(request->log.dst);
106 request->log.dst = dst;
107 }
108 request->log.lvl = L_DBG_LVL_OFF;
109 return;
110 }
111
112 /*
113 * Remove a particular log destination.
114 */
115 if (lvl == L_DBG_LVL_OFF) {
116 log_dst_t **last;
117
118 last = &request->log.dst;
119 while (*last) {
120 dst = *last;
121 if (((fr_log_t *)dst->uctx)->parent == log_dst) {
122 *last = dst->next;
123 talloc_free(dst);
124 if (!request->log.dst) request->log.lvl = L_DBG_LVL_OFF;
125 return;
126 }
127
128 last = &(dst->next);
129 }
130
131 return;
132 }
133
134 /*
135 * Change the debug level of an existing destination.
136 */
137 for (dst = request->log.dst; dst != NULL; dst = dst->next) {
138 if (((fr_log_t *)dst->uctx)->parent == log_dst) {
139 dst->lvl = lvl;
140 if (lvl > request->log.lvl) request->log.lvl = lvl;
141 return;
142 }
143 }
144
145 /*
146 * Not found, add a new log destination.
147 */
148 MEM(dst = talloc_zero(request, log_dst_t));
149
150 dst->func = vlog_request;
151 dst->uctx = log_dst;
152
153 dst->lvl = lvl;
154 if (lvl > request->log.lvl) request->log.lvl = lvl;
155 dst->next = request->log.dst;
156
157 request->log.dst = dst;
158}
159
160static inline void CC_HINT(always_inline) request_log_init_child(request_t *child, request_t const *parent)
161{
162 /*
163 * Copy debug information.
164 */
165 memcpy(&(child->log), &(parent->log), sizeof(child->log));
166 child->log.indent.unlang = 0; /* Apart from the indent which we reset */
167 child->log.indent.module = 0; /* Apart from the indent which we reset */
168 child->log.lvl = parent->log.lvl;
169}
170
171static inline void CC_HINT(always_inline) request_log_init_detachable(request_t *child, request_t const *parent)
172{
174
175 /*
176 * Ensure that we use our own version of the logging
177 * information, and not the original request one.
178 */
179 child->log.dst = talloc_zero(child, log_dst_t);
180 memcpy(child->log.dst, parent->log.dst, sizeof(*child->log.dst));
181}
182
183static inline CC_HINT(always_inline) int request_detachable_init(request_t *child, request_t *parent)
184{
185 /*
186 * Associate the child with the parent, using the child's
187 * pointer as a unique identifier. Free it if the parent
188 * goes away, but don't persist it across
189 * challenge-response boundaries.
190 */
191 if (request_data_talloc_add(parent, child, 0, request_t, child, true, true, false) < 0) return -1;
192
193 return 0;
194}
195
196static inline CC_HINT(always_inline) int request_child_init(request_t *child, request_t *parent)
197{
198 child->number = parent->child_number++;
199 if (!child->proto_dict) {
200 child->proto_dict = parent->proto_dict;
201 child->local_dict = parent->proto_dict;
202 }
203
204 if ((parent->seq_start == 0) || (parent->number == parent->seq_start)) {
205 child->name = talloc_typed_asprintf(child, "%s.%" PRIu64, parent->name, child->number);
206 } else {
207 child->name = talloc_typed_asprintf(child, "(%s,%" PRIu64 ").%" PRIu64,
208 parent->name, parent->seq_start, child->number);
209 }
210 child->seq_start = 0; /* children always start with their own sequence */
211 child->parent = parent;
212
213 /*
214 * For new server support.
215 *
216 * FIXME: Key instead off of a "virtual server" data structure.
217 *
218 * FIXME: Permit different servers for inner && outer sessions?
219 */
220 child->packet = fr_packet_alloc(child, true);
221 if (!child->packet) {
222 talloc_free(child);
223 return -1;
224 }
225
226 child->reply = fr_packet_alloc(child, false);
227 if (!child->reply) {
228 talloc_free(child);
229 return -1;
230 }
231
232 return 0;
233}
234
235/** Setup logging and other fields for a request
236 *
237 * @param[in] file the request was allocated in.
238 * @param[in] line the request was allocated on.
239 * @param[in] request to (re)-initialise.
240 * @param[in] type of request to initialise.
241 * @param[in] args Other optional arguments.
242 */
243static inline CC_HINT(always_inline) int request_init(char const *file, int line,
244 request_t *request, request_type_t type,
246{
247 fr_dict_t const *dict;
248
249 /*
250 * Sanity checks for different requests types
251 */
252 switch (type) {
255
256 if (!fr_cond_assert_msg(!args->parent, "External requests must NOT have a parent")) return -1;
257
258 fr_assert(args->namespace);
259
260 dict = args->namespace;
261 break;
262
264 if (!args || !args->namespace) {
265 dict = fr_dict_internal();
266 } else {
267 dict = args->namespace;
268 }
269 break;
270
272 fr_assert_fail("Detached requests should start as type == REQUEST_TYPE_INTERNAL, "
273 "args->detachable and be detached later");
274 return -1;
275 }
276
277 *request = (request_t){
278#ifndef NDEBUG
279 .magic = REQUEST_MAGIC,
280#endif
281 .type = type,
282 .master_state = REQUEST_ACTIVE,
283 .proto_dict = fr_dict_proto_dict(dict),
284 .local_dict = dict,
285 .component = "<pre-core>",
286 .flags = {
287 .detachable = args && args->detachable,
288 },
289 .alloc_file = file,
290 .alloc_line = line
291 };
292
293
294 /*
295 * Initialise the stack
296 */
297 MEM(request->stack = unlang_interpret_stack_alloc(request));
298
299 /*
300 * Initialise the request data list
301 */
302 request_data_list_init(&request->data);
303
304 {
305 fr_pair_t *vp = NULL, *pair_root;
306
307 /*
308 * Alloc the pair root this is a
309 * special pair which does not
310 * free its children when it is
311 * freed.
312 */
313 pair_root = fr_pair_root_afrom_da(request, request_attr_root);
314 if (unlikely(!pair_root)) return -1;
315 request->pair_root = pair_root;
316
317 /*
318 * Copy all the pair lists over into
319 * the request. We then check for
320 * the any uninitialised lists and
321 * create them locally.
322 */
323 if (args) memcpy(&request->pair_list, &args->pair_list, sizeof(request->pair_list));
324
325#define list_init(_ctx, _list) \
326 do { \
327 vp = fr_pair_afrom_da(_ctx, request_attr_##_list); \
328 if (unlikely(!vp)) { \
329 talloc_free(pair_root); \
330 memset(&request->pair_list, 0, sizeof(request->pair_list)); \
331 return -1; \
332 } \
333 fr_pair_append(&pair_root->children, vp); \
334 request->pair_list._list = vp; \
335 } while(0)
336
337 if (!request->pair_list.request) list_init(request->pair_root, request);
338 if (!request->pair_list.reply) list_init(request->pair_root, reply);
339 if (!request->pair_list.control) list_init(request->pair_root, control);
340 if (!request->pair_list.local) list_init(request->pair_root, local);
341 if (!request->pair_list.state) {
342 list_init(NULL, state);
343#ifndef NDEBUG
344 talloc_set_destructor(request->pair_list.state, _state_ctx_free);
345#endif
346 }
347 }
348
349 /*
350 * Initialise packets and additional
351 * fields if this is going to be a
352 * child request.
353 */
354 if (args && args->parent) {
355 if (request_child_init(request, args->parent) < 0) return -1;
356
357 if (args->detachable) {
358 if (request_detachable_init(request, args->parent) < 0) return -1;
359 request_log_init_detachable(request, args->parent);
360 } else {
361 request_log_init_child(request, args->parent);
362 }
363 } else {
365 }
366 return 0;
367}
368
369/** Callback for freeing a request struct
370 *
371 * @param[in] request to free or return to the free list.
372 * @return
373 * - 0 in the request was freed.
374 * - -1 if the request was inserted into the free list.
375 */
376static int _request_free(request_t *request)
377{
378 fr_assert_msg(!fr_heap_entry_inserted(request->time_order_id),
379 "alloced %s:%i: %s still in the time_order heap ID %i",
380 request->alloc_file,
381 request->alloc_line,
382 request->name ? request->name : "(null)", request->time_order_id);
383 fr_assert_msg(!fr_heap_entry_inserted(request->runnable_id),
384 "alloced %s:%i: %s still in the runnable heap ID %i",
385 request->alloc_file,
386 request->alloc_line,
387 request->name ? request->name : "(null)", request->runnable_id);
388
389 RDEBUG3("Request freed (%p)", request);
390
391 /*
392 * Reinsert into the free list if it's not already
393 * in the free list.
394 *
395 * If it *IS* already in the free list, then free it.
396 */
397 if (unlikely(fr_dlist_entry_in_list(&request->free_entry))) {
398 fr_dlist_entry_unlink(&request->free_entry); /* Don't trust the list head to be available */
399 goto really_free;
400 }
401
402 /*
403 * We keep a buffer of <active> + N requests per
404 * thread, to avoid spurious allocations.
405 */
407 fr_dlist_head_t *free_list;
408
409 if (request->session_state_ctx) {
410 fr_assert(talloc_parent(request->session_state_ctx) != request); /* Should never be directly parented */
411 TALLOC_FREE(request->session_state_ctx); /* Not parented from the request */
412 }
413 free_list = request_free_list;
414
415 /*
416 * Reinitialise the request
417 */
418 talloc_free_children(request);
419
420 memset(request, 0, sizeof(*request));
421 request->component = "free_list";
422#ifndef NDEBUG
423 /*
424 * So we don't trip heap asserts
425 * if the request is freed out of
426 * the free list.
427 */
428 request->time_order_id = FR_HEAP_INDEX_INVALID;
429 request->runnable_id = FR_HEAP_INDEX_INVALID;
430#endif
431
432 /*
433 * Reinsert into the free list
434 */
435 fr_dlist_insert_head(free_list, request);
436 request_free_list = free_list;
437
438 return -1; /* Prevent free */
439 }
440
441
442 /*
443 * Ensure anything that might reference the request is
444 * freed before it is.
445 */
446 talloc_free_children(request);
447
448really_free:
449 /*
450 * state_ctx is parented separately.
451 */
452 if (request->session_state_ctx) TALLOC_FREE(request->session_state_ctx);
453
454#ifndef NDEBUG
455 request->magic = 0x01020304; /* set the request to be nonsense */
456#endif
457
458 return 0;
459}
460
461/** Free any free requests when the thread is joined
462 *
463 */
465{
466 fr_dlist_head_t *list = talloc_get_type_abort(arg, fr_dlist_head_t);
467 request_t *request;
468
469 /*
470 * See the destructor for why this works
471 */
472 while ((request = fr_dlist_head(list))) if (talloc_free(request) < 0) return -1;
473 return talloc_free(list);
474}
475
476static inline CC_HINT(always_inline) request_t *request_alloc_pool(TALLOC_CTX *ctx)
477{
478 request_t *request;
479
480 /*
481 * Only allocate requests in the NULL
482 * ctx. There's no scenario where it's
483 * appropriate to allocate them in a
484 * pool, and using a strict talloc
485 * hierarchy means that child requests
486 * cannot be returned to a free list
487 * and would have to be freed.
488 */
489 MEM(request = talloc_pooled_object(ctx, request_t,
490 1 + /* Stack pool */
491 UNLANG_STACK_MAX + /* Stack Frames */
492 2 + /* packets */
493 10, /* extra */
494 (UNLANG_FRAME_PRE_ALLOC * UNLANG_STACK_MAX) + /* Stack memory */
495 (sizeof(fr_pair_t) * 5) + /* pair lists and root*/
496 (sizeof(fr_packet_t) * 2) + /* packets */
497 128 /* extra */
498 ));
499 fr_assert(ctx != request);
500
501 return request;
502}
503
504/** Create a new request_t data structure
505 *
506 * @param[in] file where the request was allocated.
507 * @param[in] line where the request was allocated.
508 * @param[in] ctx to bind the request to.
509 * @param[in] type what type of request to alloc.
510 * @param[in] args Optional arguments.
511 * @return
512 * - A request on success.
513 * - NULL on error.
514 */
515request_t *_request_alloc(char const *file, int line, TALLOC_CTX *ctx,
517{
518 request_t *request;
519 fr_dlist_head_t *free_list;
520
521 /*
522 * Setup the free list, or return the free
523 * list for this thread.
524 */
526 MEM(free_list = talloc(NULL, fr_dlist_head_t));
527 fr_dlist_init(free_list, request_t, free_entry);
529 } else {
530 free_list = request_free_list;
531 }
532
533 request = fr_dlist_head(free_list);
534 if (!request) {
535 /*
536 * Must be allocated with in the NULL ctx
537 * as chunk is returned to the free list.
538 */
539 request = request_alloc_pool(NULL);
540 talloc_set_destructor(request, _request_free);
541 } else {
542 /*
543 * Remove from the free list, as we're
544 * about to use it!
545 */
546 fr_dlist_remove(free_list, request);
547 }
548
549 if (request_init(file, line, request, type, args) < 0) {
550 talloc_free(request);
551 return NULL;
552 }
553
554 /*
555 * Initialise entry in free list
556 */
557 fr_dlist_entry_init(&request->free_entry); /* Needs to be initialised properly, else bad things happen */
558
559 /*
560 * This is only used by src/lib/io/worker.c
561 */
562 fr_dlist_entry_init(&request->listen_entry);
563
564 /*
565 * Bind lifetime to a parent.
566 *
567 * If the parent is freed the destructor
568 * will fire, and return the request
569 * to a "top level" free list.
570 */
571 if (ctx) talloc_link_ctx(ctx, request);
572
573 return request;
574}
575
576static int _request_local_free(request_t *request)
577{
578 /*
579 * Ensure anything that might reference the request is
580 * freed before it is.
581 */
582 talloc_free_children(request);
583
584 /*
585 * state_ctx is parented separately.
586 *
587 * The reason why it's OK to do this, is if the state attributes
588 * need to persist across requests, they will already have been
589 * moved to a fr_state_entry_t, with the state pointers in the
590 * request being set to NULL, before the request is freed/
591 *
592 * Note also that we do NOT call TALLOC_FREE(), which
593 * sets state_ctx=NULL. We don't control the order in
594 * which talloc frees the children. And the parents
595 * state_ctx pointer needs to stick around so that all of
596 * the children can check it.
597 *
598 * If this assertion hits, it means that someone didn't
599 * call fr_state_store_in_parent()
600 */
601 if (request->session_state_ctx) {
602 fr_assert(!request->parent || (request->session_state_ctx != request->parent->session_state_ctx));
603
604 talloc_free(request->session_state_ctx);
605 }
606
607#ifndef NDEBUG
608 request->magic = 0x01020304; /* set the request to be nonsense */
609#endif
610
611 return 0;
612}
613
614/** Allocate a request that's not in the free list
615 *
616 * This can be useful if modules need a persistent request for their own purposes
617 * which needs to be outside of the normal free list, so that it can be freed
618 * when the module requires, not when the thread destructor runs.
619 */
620request_t *_request_local_alloc(char const *file, int line, TALLOC_CTX *ctx,
622{
623 request_t *request;
624
625 request = request_alloc_pool(ctx);
626 if (request_init(file, line, request, type, args) < 0) return NULL;
627
628 talloc_set_destructor(request, _request_local_free);
629
630 return request;
631}
632
633/** Replace the session_state_ctx with a new one.
634 *
635 * NOTHING should rewrite request->session_state_ctx.
636 *
637 * It's now a pair, and is stored in request->pair_root.
638 * So it's wrong for anyone other than this function to play games with it.
639 *
640 * @param[in] request to replace the state of.
641 * @param[in] new_state state to assign to the request.
642 * May be NULL in which case a new_state state will
643 * be alloced and assigned.
644 *
645 * @return the fr_pair_t containing the old state list.
646 */
648{
649 fr_pair_t *old = request->session_state_ctx;
650
651 fr_assert(request->session_state_ctx != NULL);
652 fr_assert(request->session_state_ctx != new_state);
653
654 fr_pair_remove(&request->pair_root->children, old);
655
656 /*
657 * Save (or delete) the existing state, and re-initialize
658 * it with a brand new one.
659 */
660 if (!new_state) MEM(new_state = fr_pair_afrom_da(NULL, request_attr_state));
661
662 request->session_state_ctx = new_state;
663
664 fr_pair_append(&request->pair_root->children, new_state);
665
666 return old;
667}
668
669/** Unlink a subrequest from its parent
670 *
671 * @note This should be used for requests in preparation for freeing them.
672 *
673 * @param[in] child request to unlink.
674 * @return
675 * - 0 on success.
676 * - -1 on failure.
677 */
679{
680 request_t *request = child->parent;
681
682 /*
683 * Already detached or not detachable
684 */
685 if (request_is_detached(child)) return 0;
686
687 if (!request_is_detachable(child)) {
688 fr_strerror_const("Request is not detachable");
689 return -1;
690 }
691
692 /*
693 * Unlink the child from the parent.
694 */
695 request_data_get(request, child, 0);
696
697 child->parent = NULL;
698
699 /*
700 * Request is now detached
701 */
702 child->type = REQUEST_TYPE_DETACHED;
703
704 /*
705 * ...and is no longer detachable.
706 */
707 child->flags.detachable = 0;
708
709 return 0;
710}
711
712static int _request_global_free(UNUSED void *uctx)
713{
715 return 0;
716}
717
718static int _request_global_init(UNUSED void *uctx)
719{
721 PERROR("%s", __FUNCTION__);
722 return -1;
723 }
725 PERROR("%s", __FUNCTION__);
727 return -1;
728 }
729 return 0;
730}
731
733{
734 int ret;
735 fr_atexit_global_once_ret(&ret, _request_global_init, _request_global_free, NULL);
736 return ret;
737}
738
739#ifdef WITH_VERIFY_PTR
740/*
741 * Verify a packet.
742 */
743static void packet_verify(char const *file, int line,
744 request_t const *request, fr_packet_t const *packet, fr_pair_list_t *list, char const *type)
745{
746 TALLOC_CTX *parent;
747
748 fr_fatal_assert_msg(packet, "CONSISTENCY CHECK FAILED %s[%i]: fr_packet_t %s pointer was NULL",
749 file, line, type);
750
751 parent = talloc_parent(packet);
752 if (parent != request) {
753 fr_log_talloc_report(packet);
755
756
757 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%i]: Expected fr_packet_t %s to be parented "
758 "by %p (%s), but parented by %p (%s)",
759 file, line, type, request, talloc_get_name(request),
760 parent, parent ? talloc_get_name(parent) : "NULL");
761 }
762
763 /*
764 * Enforce nesting at the top level. This catches minor programming bugs in the server core.
765 *
766 * If we care more, we could do these checks recursively. But the tmpl_tokenize code already
767 * enforces parent / child namespaces. So the end user shouldn't be able to break the parenting.
768 *
769 * This code really only checks for programming bugs where the C code creates a pair, and then
770 * adds it to the wrong list. This was happening during the transition from flat to nested, as
771 * the code was in the middle of being fixed. It should only happen now if the programmer
772 * forgets, and uses the wrong APIs.
773 */
774 fr_pair_list_foreach(list, vp) {
775 if (vp->da->flags.is_raw) continue;
776
777 if (vp->da->flags.internal) continue;
778
779 if (vp->da->depth > 1) {
780 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%i]: Expected fr_pair_t %s to be parented "
781 "by (%s), but it is instead at the top-level %s list",
782 file, line, vp->da->name, vp->da->parent->name, type);
783 }
784 }
785
786 PACKET_VERIFY(packet);
787}
788
789/*
790 * Catch horrible talloc errors.
791 */
792void request_verify(char const *file, int line, request_t const *request)
793{
794 request_data_t *rd = NULL;
795
796 fr_fatal_assert_msg(request, "CONSISTENCY CHECK FAILED %s[%i]: request_t pointer was NULL", file, line);
797
798 (void) talloc_get_type_abort_const(request, request_t);
799
800 fr_assert(request->magic == REQUEST_MAGIC);
801
802 fr_fatal_assert_msg(talloc_get_size(request) == sizeof(request_t),
803 "CONSISTENCY CHECK FAILED %s[%i]: expected request_t size of %zu bytes, got %zu bytes",
804 file, line, sizeof(request_t), talloc_get_size(request));
805
806 (void)talloc_get_type_abort(request->request_ctx, fr_pair_t);
807 fr_pair_list_verify(file, line, request->request_ctx, &request->request_pairs);
808 (void)talloc_get_type_abort(request->reply_ctx, fr_pair_t);
809 fr_pair_list_verify(file, line, request->reply_ctx, &request->reply_pairs);
810 (void)talloc_get_type_abort(request->control_ctx, fr_pair_t);
811 fr_pair_list_verify(file, line, request->control_ctx, &request->control_pairs);
812 (void)talloc_get_type_abort(request->session_state_ctx, fr_pair_t);
813
814#ifndef NDEBUG
815 {
816 TALLOC_CTX *parent = talloc_parent(request->session_state_ctx);
817
818 fr_assert_msg((parent == NULL) || (parent == talloc_null_ctx()),
819 "session_state_ctx must not be parented by another chunk, but is parented by %s",
820 talloc_get_name(talloc_parent(request->session_state_ctx)));
821 }
822#endif
823
824 fr_pair_list_verify(file, line, request->session_state_ctx, &request->session_state_pairs);
825 fr_pair_list_verify(file, line, request->local_ctx, &request->local_pairs);
826
827 fr_assert(request->proto_dict != NULL);
828 fr_assert(request->local_dict != NULL);
829
830 if (request->packet) {
831 packet_verify(file, line, request, request->packet, &request->request_pairs, "request");
832 }
833 if (request->reply) {
834 packet_verify(file, line, request, request->reply, &request->reply_pairs, "reply");
835 }
836
837 if (request->async) {
838 (void) talloc_get_type_abort(request->async, fr_async_t);
839 fr_assert(talloc_parent(request->async) == request);
840 }
841
842 while ((rd = fr_dlist_next(&request->data, rd))) {
843 (void) talloc_get_type_abort(rd, request_data_t);
844
845 if (request_data_persistable(rd)) {
846 fr_assert(request->session_state_ctx);
847 fr_assert(talloc_parent(rd) == request->session_state_ctx);
848 } else {
849 fr_assert(talloc_parent(rd) == request);
850 }
851 }
852}
853#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
#define fr_atexit_thread_local(_name, _free, _uctx)
Definition atexit.h:221
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:862
fr_dict_t const * fr_dict_proto_dict(fr_dict_t const *dict)
Definition dict_util.c:4979
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:272
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:285
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:4097
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4617
#define fr_dict_autoload(_to_load)
Definition dict.h:859
Specifies an attribute which must be present for the module to function.
Definition dict.h:271
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:284
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition dlist.h:260
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.
Definition dlist.h:486
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition dlist.h:638
static bool fr_dlist_entry_in_list(fr_dlist_t const *entry)
Check if a list entry is part of a list.
Definition dlist.h:163
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.
Definition dlist.h:146
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
Definition dlist.h:939
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
Definition dlist.h:338
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
Head of a doubly linked list.
Definition dlist.h:51
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:1064
#define UNLANG_STACK_MAX
The maximum depth of the stack.
Definition interpret.h:38
#define UNLANG_FRAME_PRE_ALLOC
How much memory we pre-alloc for each frame.
Definition interpret.h:39
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
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:43
fr_log_t default_log
Definition log.c:291
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:245
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:1347
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:285
#define fr_assert(_expr)
Definition rad_assert.h:38
static int request_child_init(request_t *child, request_t *parent)
Definition request.c:196
fr_dict_attr_t const * request_attr_request
Definition request.c:43
static int _request_global_init(UNUSED void *uctx)
Definition request.c:718
static void request_log_init_orphan(request_t *request)
Definition request.c:75
static int _request_local_free(request_t *request)
Definition request.c:576
static request_t * request_alloc_pool(TALLOC_CTX *ctx)
Definition request.c:476
#define list_init(_ctx, _list)
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:620
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:647
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:183
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
request_t * _request_alloc(char const *file, int line, TALLOC_CTX *ctx, request_type_t type, request_init_args_t const *args)
Create a new request_t data structure.
Definition request.c:515
static int _request_free_list_free_on_exit(void *arg)
Free any free requests when the thread is joined.
Definition request.c:464
static _Thread_local fr_dlist_head_t * request_free_list
The thread local free list.
Definition request.c:64
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:98
int request_global_init(void)
Definition request.c:732
int request_detach(request_t *child)
Unlink a subrequest from its parent.
Definition request.c:678
static int _state_ctx_free(fr_pair_t *state)
Definition request.c:67
fr_dict_attr_t const * request_attr_root
Definition request.c:42
static 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:243
static int _request_free(request_t *request)
Callback for freeing a request struct.
Definition request.c:376
static void request_log_init_child(request_t *child, request_t const *parent)
Definition request.c:160
static void request_log_init_detachable(request_t *child, request_t const *parent)
Definition request.c:171
static int _request_global_free(UNUSED void *uctx)
Definition request.c:712
#define request_is_detached(_x)
Definition request.h:160
#define REQUEST_MAGIC
Definition request.h:57
request_type_t
Definition request.h:151
@ REQUEST_TYPE_EXTERNAL
A request received on the wire.
Definition request.h:152
@ REQUEST_TYPE_INTERNAL
A request generated internally.
Definition request.h:153
@ REQUEST_TYPE_DETACHED
A request that was generated internally, but is now detached (not associated with a parent request....
Definition request.h:154
#define request_is_detachable(_x)
Definition request.h:161
@ REQUEST_ACTIVE
Request is active (running or runnable)
Definition request.h:61
Optional arguments for initialising requests.
Definition request.h:255
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:492
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.
Definition talloc.c:171
void * talloc_null_ctx(void)
Retrieve the current talloc NULL ctx.
Definition talloc.c:53
#define talloc_get_type_abort_const
Definition talloc.h:282
#define talloc_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:180
#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:94
#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:845
#define fr_strerror_const(_msg)
Definition strerror.h:223