25 RCSID(
"$Id: 91cfebee5ad5df016cc62e07cc05f50d46f556a1 $")
27 #include <freeradius-devel/server/request.h>
28 #include <freeradius-devel/server/request_data.h>
29 #include <freeradius-devel/unlang/interpret.h>
31 #include <freeradius-devel/util/debug.h>
32 #include <freeradius-devel/util/atexit.h>
71 DEBUG4(
"state-ctx %p freed", state);
83 if (!request->log.dst) {
84 request->log.dst = talloc_zero(request,
log_dst_t);
86 memset(request->log.dst, 0,
sizeof(*request->log.dst));
105 while (request->log.dst) {
106 dst = request->log.dst->next;
108 request->log.dst = dst;
120 last = &request->log.dst;
139 for (dst = request->log.dst; dst != NULL; dst = dst->
next) {
142 if (lvl > request->log.lvl) request->log.lvl = lvl;
156 if (lvl > request->log.lvl) request->log.lvl = lvl;
157 dst->
next = request->log.dst;
159 request->log.dst = dst;
167 memcpy(&(child->log), &(
parent->log),
sizeof(child->log));
168 child->log.indent.unlang = 0;
169 child->log.indent.module = 0;
170 child->log.lvl =
parent->log.lvl;
181 child->log.dst = talloc_zero(child,
log_dst_t);
182 memcpy(child->log.dst,
parent->log.dst,
sizeof(*child->log.dst));
200 child->number =
parent->child_number++;
201 if (!child->dict) child->dict =
parent->dict;
209 child->seq_start = 0;
220 if (!child->packet) {
259 fr_assert_fail(
"Detached requests should start as type == REQUEST_TYPE_INTERNAL, "
260 "args->detachable and be detached later");
270 .dict =
args->namespace,
271 .component =
"<pre-core>",
273 .detachable =
args->detachable
300 if (
unlikely(!pair_root))
return -1;
301 request->pair_root = pair_root;
309 memcpy(&request->pair_list, &
args->pair_list,
sizeof(request->pair_list));
311 #define list_init(_ctx, _list) \
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)); \
319 fr_pair_append(&pair_root->children, vp); \
320 request->pair_list._list = vp; \
323 if (!request->pair_list.request)
list_init(request->pair_root, request);
324 if (!request->pair_list.reply)
list_init(request->pair_root, reply);
326 if (!request->pair_list.local)
list_init(request->pair_root, local);
327 if (!request->pair_list.state) {
343 if (
args->detachable) {
365 "alloced %s:%i: %s still in the time_order heap ID %i",
368 request->name ? request->name :
"(null)", request->time_order_id);
370 "alloced %s:%i: %s still in the runnable heap ID %i",
373 request->name ? request->name :
"(null)", request->runnable_id);
375 RDEBUG3(
"Request freed (%p)", request);
395 if (request->session_state_ctx) {
396 fr_assert(talloc_parent(request->session_state_ctx) != request);
397 TALLOC_FREE(request->session_state_ctx);
404 talloc_free_children(request);
406 memset(request, 0,
sizeof(*request));
407 request->component =
"free_list";
432 talloc_free_children(request);
438 if (request->session_state_ctx) TALLOC_FREE(request->session_state_ctx);
441 request->magic = 0x01020304;
570 talloc_free_children(request);
589 if (request->session_state_ctx) {
590 fr_assert(!request->parent || (request->session_state_ctx != request->parent->session_state_ctx));
596 request->magic = 0x01020304;
639 fr_pair_t *old = request->session_state_ctx;
641 fr_assert(request->session_state_ctx != NULL);
642 fr_assert(request->session_state_ctx != new_state);
652 request->session_state_ctx = new_state;
687 child->parent = NULL;
697 child->flags.detachable = 0;
711 PERROR(
"%s", __FUNCTION__);
715 PERROR(
"%s", __FUNCTION__);
729 #ifdef WITH_VERIFY_PTR
733 static void packet_verify(
char const *
file,
int line,
738 fr_fatal_assert_msg(packet,
"CONSISTENCY CHECK FAILED %s[%i]: fr_packet_t %s pointer was NULL",
741 parent = talloc_parent(packet);
748 "by %p (%s), but parented by %p (%s)",
765 if (
vp->
da->flags.is_raw)
continue;
767 if (
vp->
da->flags.internal)
continue;
769 if (
vp->
da->depth > 1) {
771 "by (%s), but it is instead at the top-level %s list",
793 "CONSISTENCY CHECK FAILED %s[%i]: expected request_t size of %zu bytes, got %zu bytes",
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);
806 TALLOC_CTX *
parent = talloc_parent(request->session_state_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)));
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);
817 if (request->packet) {
818 packet_verify(
file,
line, request, request->packet, &request->request_pairs,
"request");
820 if (request->reply) {
821 packet_verify(
file,
line, request, request->reply, &request->reply_pairs,
"reply");
824 if (request->async) {
825 (void) talloc_get_type_abort(request->async,
fr_async_t);
826 fr_assert(talloc_parent(request->async) == request);
832 if (request_data_persistable(rd)) {
834 fr_assert(talloc_parent(rd) == request->session_state_ctx);
#define fr_atexit_thread_local(_name, _free, _uctx)
void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request)
static fr_control_t * control
fr_dcursor_eval_t void const * uctx
int fr_log_talloc_report(TALLOC_CTX const *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_fatal_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define fr_dict_autofree(_to_free)
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
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.
#define fr_dict_autoload(_to_load)
Specifies an attribute which must be present for the module to function.
Specifies a dictionary which must be loaded/loadable for the module to function.
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
static bool fr_dlist_entry_in_list(fr_dlist_t const *entry)
Check if a list entry is part of a list.
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.
static unsigned int fr_dlist_num_elements(fr_dlist_head_t const *head)
Return the number of elements in the dlist.
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.
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
static int fr_dlist_insert_head(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the head of a list.
static void fr_dlist_entry_init(fr_dlist_t *entry)
Initialise a linked list without metadata.
Head of a doubly linked list.
static bool fr_heap_entry_inserted(fr_heap_index_t heap_idx)
Check if an entry is inserted into a heap.
#define FR_HEAP_INDEX_INVALID
void * unlang_interpret_stack_alloc(TALLOC_CTX *ctx)
Allocate a new unlang stack.
#define UNLANG_STACK_MAX
The maximum depth of the stack.
#define UNLANG_FRAME_PRE_ALLOC
How much memory we pre-alloc for each frame.
Minimal data structure to use the new code.
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.
fr_log_lvl_t lvl
Log messages with lvl >= to this should be logged.
void * uctx
Context to pass to the logging function.
log_dst_t * next
Next logging destination.
log_func_t func
Function to call to log to this destination.
@ L_DBG_LVL_DISABLE
Don't print messages.
@ L_DBG_LVL_OFF
No debug messages.
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
@ FR_TYPE_GROUP
A grouping of other attributes.
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.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
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.
struct request_s request_t
static int request_child_init(request_t *child, request_t *parent)
fr_dict_attr_t const * request_attr_request
static int _request_global_init(UNUSED void *uctx)
static void request_log_init_orphan(request_t *request)
static request_init_args_t default_args
static int _request_local_free(request_t *request)
#define list_init(_ctx, _list)
static request_t * request_alloc_pool(TALLOC_CTX *ctx)
fr_dict_autoload_t request_dict[]
static fr_dict_t const * dict_freeradius
fr_dict_attr_t const * request_attr_control
static int request_detachable_init(request_t *child, request_t *parent)
fr_dict_attr_t const * request_attr_local
fr_dict_attr_t const * request_attr_state
fr_dict_attr_t const * request_attr_reply
fr_dict_attr_autoload_t request_dict_attr[]
static int _request_free_list_free_on_exit(void *arg)
Free any free requests when the thread is joined.
static _Thread_local fr_dlist_head_t * request_free_list
The thread local free list.
void request_log_prepend(request_t *request, fr_log_t *log_dst, fr_log_lvl_t lvl)
Prepend another logging destination to the list.
int request_global_init(void)
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.
int request_detach(request_t *child)
Unlink a subrequest from its parent.
static int _state_ctx_free(fr_pair_t *state)
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.
fr_dict_attr_t const * request_attr_root
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.
static int _request_free(request_t *request)
Callback for freeing a request struct.
static void request_log_init_child(request_t *child, request_t const *parent)
static void request_log_init_detachable(request_t *child, request_t const *parent)
fr_pair_t * request_state_replace(request_t *request, fr_pair_t *new_state)
Replace the session_state_ctx with a new one.
static int _request_global_free(UNUSED void *uctx)
#define request_is_detached(_x)
@ REQUEST_TYPE_EXTERNAL
A request received on the wire.
@ REQUEST_TYPE_INTERNAL
A request generated internally.
@ REQUEST_TYPE_DETACHED
A request that was generated internally, but is now detached (not associated with a parent request....
#define request_is_detachable(_x)
@ REQUEST_ACTIVE
Request is active (running or runnable)
Optional arguments for initialising requests.
void * request_data_get(request_t *request, void const *unique_ptr, int unique_int)
Get opaque data from a request.
void request_data_list_init(fr_dlist_head_t *data)
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.
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_aka_sim_id_type_t type
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
void * talloc_null_ctx(void)
Retrieve the current talloc NULL ctx.
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.
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
#define talloc_get_type_abort_const
#define talloc_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
#define PACKET_VERIFY(_x)
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
#define fr_strerror_const(_msg)