The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: 5653d8d5a2f7eec40390fb4dbfb404fab180023e $
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: 5653d8d5a2f7eec40390fb4dbfb404fab180023e $")
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" },
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 },
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 if (!parent->log.dst) return;
174
175 MEM(child->log.dst = talloc_zero(child, log_dst_t));
176 memcpy(child->log.dst, parent->log.dst, sizeof(*child->log.dst));
177}
178
179static inline CC_HINT(always_inline) int request_detachable_init(request_t *child, request_t *parent)
180{
181 /*
182 * Associate the child with the parent, using the child's
183 * pointer as a unique identifier. Free it if the parent
184 * goes away, but don't persist it across
185 * challenge-response boundaries.
186 */
187 if (request_data_talloc_add(parent, child, 0, request_t, child, true, true, false) < 0) return -1;
188
189 return 0;
190}
191
192static inline CC_HINT(always_inline) int request_child_init(request_t *child, request_t *parent)
193{
194 child->number = parent->child_number++;
195 if (!child->proto_dict) {
196 child->proto_dict = parent->proto_dict;
197 child->local_dict = parent->proto_dict;
198 }
199
200 if ((parent->seq_start == 0) || (parent->number == parent->seq_start)) {
201 child->name = talloc_typed_asprintf(child, "%s.%" PRIu64, parent->name, child->number);
202 } else {
203 child->name = talloc_typed_asprintf(child, "(%s,%" PRIu64 ").%" PRIu64,
204 parent->name, parent->seq_start, child->number);
205 }
206 child->seq_start = 0; /* children always start with their own sequence */
207 child->parent = parent;
208
209 /*
210 * For new server support.
211 *
212 * FIXME: Key instead off of a "virtual server" data structure.
213 *
214 * FIXME: Permit different servers for inner && outer sessions?
215 */
216 child->packet = fr_packet_alloc(child, true);
217 if (!child->packet) {
218 talloc_free(child);
219 return -1;
220 }
221
222 child->reply = fr_packet_alloc(child, false);
223 if (!child->reply) {
224 talloc_free(child);
225 return -1;
226 }
227
228 return 0;
229}
230
231/** Setup logging and other fields for a request
232 *
233 * @param[in] file the request was allocated in.
234 * @param[in] line the request was allocated on.
235 * @param[in] request to (re)-initialise.
236 * @param[in] type of request to initialise.
237 * @param[in] args Other optional arguments.
238 */
239int _request_init(char const *file, int line,
240 request_t *request, request_type_t type,
242{
243 fr_dict_t const *dict;
244
245 /*
246 * Sanity checks for different requests types
247 */
248 switch (type) {
251
252 if (!fr_cond_assert_msg(!args->parent, "External requests must NOT have a parent")) return -1;
253
254 fr_assert(args->namespace);
255
256 dict = args->namespace;
257 break;
258
260 if (!args || !args->namespace) {
262 } else {
263 dict = args->namespace;
264 }
265 break;
266
268 fr_assert_fail("Detached requests should start as type == REQUEST_TYPE_INTERNAL, "
269 "args->detachable and be detached later");
270 return -1;
271
272 /* Quiet GCC */
273 default:
274 fr_assert_fail("Invalid request type");
275 return -1;
276 }
277
278 *request = (request_t){
279#ifndef NDEBUG
280 .magic = REQUEST_MAGIC,
281#endif
282 .type = type,
283 .master_state = REQUEST_ACTIVE,
284 .proto_dict = fr_dict_proto_dict(dict),
285 .local_dict = dict,
286 .component = "<pre-core>",
287 .flags = {
288 .detachable = args && args->detachable,
289 },
290 .alloc_file = file,
291 .alloc_line = line
292 };
293
294
295 /*
296 * Initialise the stack
297 */
298 MEM(request->stack = unlang_interpret_stack_alloc(request));
299
300 /*
301 * Initialise the request data list
302 */
303 request_data_list_init(&request->data);
304
305 {
306 fr_pair_t *vp = NULL, *pair_root;
307
308 /*
309 * Alloc the pair root this is a
310 * special pair which does not
311 * free its children when it is
312 * freed.
313 */
314 pair_root = fr_pair_root_afrom_da(request, request_attr_root);
315 if (unlikely(!pair_root)) return -1;
316 request->pair_root = pair_root;
317
318 /*
319 * Copy all the pair lists over into
320 * the request. We then check for
321 * the any uninitialised lists and
322 * create them locally.
323 */
324 if (args) memcpy(&request->pair_list, &args->pair_list, sizeof(request->pair_list));
325
326#define list_init(_ctx, _list) \
327 do { \
328 vp = fr_pair_afrom_da(_ctx, request_attr_##_list); \
329 if (unlikely(!vp)) { \
330 talloc_free(pair_root); \
331 memset(&request->pair_list, 0, sizeof(request->pair_list)); \
332 return -1; \
333 } \
334 fr_pair_append(&pair_root->children, vp); \
335 request->pair_list._list = vp; \
336 } while(0)
337
338 if (!request->pair_list.request) list_init(request->pair_root, request);
339 if (!request->pair_list.reply) list_init(request->pair_root, reply);
340 if (!request->pair_list.control) list_init(request->pair_root, control);
341 if (!request->pair_list.local) list_init(request->pair_root, local);
342 if (!request->pair_list.state) {
343 list_init(NULL, state);
344#ifndef NDEBUG
345 talloc_set_destructor(request->pair_list.state, _state_ctx_free);
346#endif
347 }
348 }
349
350 /*
351 * Initialise packets and additional
352 * fields if this is going to be a
353 * child request.
354 */
355 if (args && args->parent) {
356 if (request_child_init(request, args->parent) < 0) return -1;
357
358 if (args->detachable) {
359 if (request_detachable_init(request, args->parent) < 0) return -1;
360 request_log_init_detachable(request, args->parent);
361 } else {
362 request_log_init_child(request, args->parent);
363 }
364 } else {
366 }
367
368 /*
369 * This is only used by src/lib/io/worker.c
370 */
371 fr_dlist_entry_init(&request->listen_entry);
372
373 return 0;
374}
375
376/** Callback for slabs to deinitialise the request
377 *
378 * Does not need to be called for local requests.
379 *
380 * @param[in] request deinitialise
381 * @return
382 * - 0 in the request was deinitialised.
383 * - -1 if the request is in an unexpected state.
384 */
386{
387 fr_assert_msg(!fr_timer_armed(request->timeout),
388 "alloced %s:%i: %s still in the timeout sublist",
389 request->alloc_file,
390 request->alloc_line,
391 request->name ? request->name : "(null)");
392 fr_assert_msg(!fr_heap_entry_inserted(request->runnable),
393 "alloced %s:%i: %s still in the runnable heap ID %i",
394 request->alloc_file,
395 request->alloc_line,
396 request->name ? request->name : "(null)", request->runnable);
397
398 RDEBUG3("Request deinitialising (%p)", request);
399
400 /*
401 * state_ctx is parented separately.
402 */
403 if (request->session_state_ctx) TALLOC_FREE(request->session_state_ctx);
404
405 /*
406 * Zero out everything.
407 */
408 memset(request, 0, sizeof(*request));
409
410#ifndef NDEBUG
411 request->component = "free_list";
412 request->runnable = FR_HEAP_INDEX_INVALID;
413 request->magic = 0x01020304; /* set the request to be nonsense */
414#endif
415
416 return 0;
417}
418
419static inline CC_HINT(always_inline) request_t *request_alloc_pool(TALLOC_CTX *ctx)
420{
421 request_t *request;
422
423 /*
424 * Only allocate requests in the NULL
425 * ctx. There's no scenario where it's
426 * appropriate to allocate them in a
427 * pool, and using a strict talloc
428 * hierarchy means that child requests
429 * cannot be returned to a free list
430 * and would have to be freed.
431 */
432 MEM(request = talloc_pooled_object(ctx, request_t,
435 fr_assert(ctx != request);
436
437 return request;
438}
439
440static int _request_local_free(request_t *request)
441{
442 RDEBUG4("Local request freed (%p)", request);
443
444 /*
445 * Ensure anything that might reference the request is
446 * freed before it is.
447 */
448 talloc_free_children(request);
449
450 /*
451 * state_ctx is parented separately.
452 *
453 * The reason why it's OK to do this, is if the state attributes
454 * need to persist across requests, they will already have been
455 * moved to a fr_state_entry_t, with the state pointers in the
456 * request being set to NULL, before the request is freed/
457 *
458 * Note also that we do NOT call TALLOC_FREE(), which
459 * sets state_ctx=NULL. We don't control the order in
460 * which talloc frees the children. And the parents
461 * state_ctx pointer needs to stick around so that all of
462 * the children can check it.
463 *
464 * If this assertion hits, it means that someone didn't
465 * call fr_state_store_in_parent()
466 */
467 if (request->session_state_ctx) {
468 fr_assert(!request->parent || (request->session_state_ctx != request->parent->session_state_ctx));
469
470 talloc_free(request->session_state_ctx);
471 }
472
473#ifndef NDEBUG
474 request->magic = 0x01020304; /* set the request to be nonsense */
475#endif
476
477 return 0;
478}
479
480/** Allocate a request that's not in the free list
481 *
482 * This can be useful if modules need a persistent request for their own purposes
483 * which needs to be outside of the normal free list, so that it can be freed
484 * when the module requires, not when the thread destructor runs.
485 */
486request_t *_request_local_alloc(char const *file, int line, TALLOC_CTX *ctx,
488{
489 request_t *request;
490
491 request = request_alloc_pool(ctx);
492 if (_request_init(file, line, request, type, args) < 0) return NULL;
493
494 talloc_set_destructor(request, _request_local_free);
495
496 return request;
497}
498
499/** Replace the session_state_ctx with a new one.
500 *
501 * NOTHING should rewrite request->session_state_ctx.
502 *
503 * It's now a pair, and is stored in request->pair_root.
504 * So it's wrong for anyone other than this function to play games with it.
505 *
506 * @param[in] request to replace the state of.
507 * @param[in] new_state state to assign to the request.
508 * May be NULL in which case a new_state state will
509 * be alloced and assigned.
510 *
511 * @return the fr_pair_t containing the old state list.
512 */
514{
515 fr_pair_t *old = request->session_state_ctx;
516
517 fr_assert(request->session_state_ctx != NULL);
518 fr_assert(request->session_state_ctx != new_state);
519
520 fr_pair_remove(&request->pair_root->children, old);
521
522 /*
523 * Save (or delete) the existing state, and re-initialize
524 * it with a brand new one.
525 */
526 if (!new_state) MEM(new_state = fr_pair_afrom_da(NULL, request_attr_state));
527
528 request->session_state_ctx = new_state;
529
530 fr_pair_append(&request->pair_root->children, new_state);
531
532 return old;
533}
534
535/** Unlink a subrequest from its parent
536 *
537 * @note This should be used for requests in preparation for freeing them.
538 *
539 * @param[in] child request to unlink.
540 * @return
541 * - 0 on success.
542 * - -1 on failure.
543 */
545{
546 request_t *request = child->parent;
547
548 /*
549 * Already detached or not detachable
550 */
551 if (request_is_detached(child)) return 0;
552
553 if (!request_is_detachable(child)) {
554 fr_strerror_const("Request is not detachable");
555 return -1;
556 }
557
558 /*
559 * Unlink the child from the parent.
560 */
561 request_data_get(request, child, 0);
562
563 child->parent = NULL;
564
565 /*
566 * Request is now detached
567 */
568 child->type = REQUEST_TYPE_DETACHED;
569
570 /*
571 * ...and is no longer detachable.
572 */
573 child->flags.detachable = 0;
574
575 return 0;
576}
577
578static int _request_global_free(UNUSED void *uctx)
579{
581 return 0;
582}
583
584static int _request_global_init(UNUSED void *uctx)
585{
587 PERROR("%s", __FUNCTION__);
588 return -1;
589 }
591 PERROR("%s", __FUNCTION__);
593 return -1;
594 }
595 return 0;
596}
597
599{
600 int ret;
601 fr_atexit_global_once_ret(&ret, _request_global_init, _request_global_free, NULL);
602 return ret;
603}
604
605#ifdef WITH_VERIFY_PTR
606/*
607 * Verify a packet.
608 */
609static void packet_verify(char const *file, int line,
610 request_t const *request, fr_packet_t const *packet, fr_pair_list_t *list, char const *type)
611{
612 TALLOC_CTX *parent;
613
614 fr_fatal_assert_msg(packet, "CONSISTENCY CHECK FAILED %s[%i]: fr_packet_t %s pointer was NULL",
615 file, line, type);
616
617 parent = talloc_parent(packet);
618 if (parent != request) {
619 fr_log_talloc_report(packet);
621
622
623 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%i]: Expected fr_packet_t %s to be parented "
624 "by %p (%s), but parented by %p (%s)",
625 file, line, type, request, talloc_get_name(request),
626 parent, parent ? talloc_get_name(parent) : "NULL");
627 }
628
629 /*
630 * Enforce nesting at the top level. This catches minor programming bugs in the server core.
631 *
632 * If we care more, we could do these checks recursively. But the tmpl_tokenize code already
633 * enforces parent / child namespaces. So the end user shouldn't be able to break the parenting.
634 *
635 * This code really only checks for programming bugs where the C code creates a pair, and then
636 * adds it to the wrong list. This was happening during the transition from flat to nested, as
637 * the code was in the middle of being fixed. It should only happen now if the programmer
638 * forgets, and uses the wrong APIs.
639 */
640 fr_pair_list_foreach(list, vp) {
641 if (vp->da->flags.is_raw) continue;
642
643 if (vp->da->flags.internal) continue;
644
645 if (vp->da->depth > 1) {
646 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%i]: Expected fr_pair_t %s to be parented "
647 "by (%s), but it is instead at the top-level %s list",
648 file, line, vp->da->name, vp->da->parent->name, type);
649 }
650 }
651
652 PACKET_VERIFY(packet);
653}
654
655/*
656 * Catch horrible talloc errors.
657 */
658void request_verify(char const *file, int line, request_t const *request)
659{
660 request_data_t *rd = NULL;
661
662 fr_fatal_assert_msg(request, "CONSISTENCY CHECK FAILED %s[%i]: request_t pointer was NULL", file, line);
663
664 (void) talloc_get_type_abort_const(request, request_t);
665
666 fr_assert(request->magic == REQUEST_MAGIC);
667
668 (void)talloc_get_type_abort(request->request_ctx, fr_pair_t);
669 fr_pair_list_verify(file, line, request->request_ctx, &request->request_pairs, true);
670 (void)talloc_get_type_abort(request->reply_ctx, fr_pair_t);
671 fr_pair_list_verify(file, line, request->reply_ctx, &request->reply_pairs, true);
672 (void)talloc_get_type_abort(request->control_ctx, fr_pair_t);
673 fr_pair_list_verify(file, line, request->control_ctx, &request->control_pairs, true);
674 (void)talloc_get_type_abort(request->session_state_ctx, fr_pair_t);
675
676#ifndef NDEBUG
677 {
678 TALLOC_CTX *parent = talloc_parent(request->session_state_ctx);
679
680 fr_assert_msg((parent == NULL) || (parent == talloc_null_ctx()),
681 "session_state_ctx must not be parented by another chunk, but is parented by %s",
682 talloc_get_name(talloc_parent(request->session_state_ctx)));
683 }
684#endif
685
686 fr_pair_list_verify(file, line, request->session_state_ctx, &request->session_state_pairs, true);
687 fr_pair_list_verify(file, line, request->local_ctx, &request->local_pairs, true);
688
689 fr_assert(request->proto_dict != NULL);
690 fr_assert(request->local_dict != NULL);
691
692 if (request->packet) {
693 packet_verify(file, line, request, request->packet, &request->request_pairs, "request");
694 }
695 if (request->reply) {
696 packet_verify(file, line, request, request->reply, &request->reply_pairs, "reply");
697 }
698
699 if (request->async) {
700 (void) talloc_get_type_abort(request->async, fr_async_t);
701 fr_assert(talloc_parent(request->async) == request);
702 }
703
704 while ((rd = fr_dlist_next(&request->data, rd))) {
705 (void) talloc_get_type_abort(rd, request_data_t);
706
707 if (request_data_persistable(rd)) {
708 fr_assert(request->session_state_ctx);
709 fr_assert(talloc_parent(rd) == request->session_state_ctx);
710 } else {
711 fr_assert(talloc_parent(rd) == request);
712 }
713 }
714}
715#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:512
#define unlikely(_x)
Definition build.h:407
#define UNUSED
Definition build.h:336
fr_dict_t * dict
Definition common.c:31
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:977
#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:183
#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:202
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition debug.h:208
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:148
#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:176
#define MEM(x)
Definition debug.h:36
#define fr_dict_autofree(_to_free)
Definition dict.h:915
fr_dict_t const * fr_dict_proto_dict(fr_dict_t const *dict)
Definition dict_util.c:5253
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
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:4372
fr_dict_t const * fr_dict_internal(void)
Definition dict_util.c:4905
#define fr_dict_autoload(_to_load)
Definition dict.h:912
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
static void fr_dlist_entry_init(fr_dlist_t *entry)
Initialise a linked list without metadata.
Definition dlist.h:120
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:537
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
talloc_free(hp)
void * unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
Allocate a new unlang stack.
Definition interpret.c:1587
Minimal data structure to use the new code.
Definition listen.h:63
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:355
#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:356
log_func_t func
Function to call to log to this destination.
Definition log.h:71
Definition log.h:70
int fr_debug_lvl
Definition log.c:41
fr_log_t default_log
Definition log.c:306
fr_log_lvl_t
Definition log.h:64
@ L_DBG_LVL_DISABLE
Don't print messages.
Definition log.h:65
@ L_DBG_LVL_OFF
No debug messages.
Definition log.h:66
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:248
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:1352
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:290
#define fr_assert(_expr)
Definition rad_assert.h:37
static int request_child_init(request_t *child, request_t *parent)
Definition request.c:192
fr_dict_attr_t const * request_attr_request
Definition request.c:43
static int _request_global_init(UNUSED void *uctx)
Definition request.c:584
static void request_log_init_orphan(request_t *request)
Definition request.c:69
static int _request_local_free(request_t *request)
Definition request.c:440
static request_t * request_alloc_pool(TALLOC_CTX *ctx)
Definition request.c:419
#define list_init(_ctx, _list)
int request_slab_deinit(request_t *request)
Callback for slabs to deinitialise the request.
Definition request.c:385
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:486
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:513
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:179
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:598
int request_detach(request_t *child)
Unlink a subrequest from its parent.
Definition request.c:544
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:239
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:578
#define request_is_detached(_x)
Definition request.h:187
#define REQUEST_MAGIC
Definition request.h:57
request_type_t
Definition request.h:178
@ REQUEST_TYPE_EXTERNAL
A request received on the wire.
Definition request.h:179
@ REQUEST_TYPE_INTERNAL
A request generated internally.
Definition request.h:180
@ REQUEST_TYPE_DETACHED
A request that was generated internally, but is now detached (not associated with a parent request....
Definition request.h:181
#define request_is_detachable(_x)
Definition request.h:188
#define REQUEST_POOL_NUM_OBJECTS
Definition request.h:68
#define REQUEST_POOL_SIZE
Definition request.h:81
@ REQUEST_ACTIVE
Request is active (running or runnable)
Definition request.h:89
Optional arguments for initialising requests.
Definition request.h:288
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:93
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:546
void * talloc_null_ctx(void)
Retrieve the current talloc NULL ctx.
Definition talloc.c:50
#define talloc_get_type_abort_const
Definition talloc.h:117
#define talloc_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
Definition talloc.h:211
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:279
static fr_slen_t parent
Definition pair.h:858
#define fr_strerror_const(_msg)
Definition strerror.h:223