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