From: Arran Cudbard-Bell Date: Thu, 25 Apr 2019 00:26:33 +0000 (-0400) Subject: Add functions to store/restore child request and session-state contents in a parent... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d79989652300a67d9fd59156a57f49af86f047d1;p=thirdparty%2Ffreeradius-server.git Add functions to store/restore child request and session-state contents in a parent request --- diff --git a/src/lib/server/request.c b/src/lib/server/request.c index 8c71defba19..43443915f09 100644 --- a/src/lib/server/request.c +++ b/src/lib/server/request.c @@ -545,6 +545,26 @@ int request_data_by_persistance(fr_dlist_head_t *out, REQUEST *request, bool per return count; } +/** Return how many request data entries exist of a given persistence + * + * @param[in] request to check in. + * @param[in] persist Whether to count persistable or non-persistable data. + * @return number of request_data_t that exist in persistable or non-persistable form + */ +int request_data_by_persistance_count(REQUEST *request, bool persist) +{ + int count = 0; + request_data_t *rd = NULL; + + while ((rd = fr_dlist_next(&request->data, rd))) { + if (rd->persist != persist) continue; + + count++; + } + + return count; +} + /** Add request data back to a request * * @note May add multiple entries (if they're linked). @@ -558,6 +578,75 @@ void request_data_restore(REQUEST *request, fr_dlist_head_t *in) fr_dlist_move(&request->data, in); } +/** Free any subrequest request data if the dlist head is freed + * + */ +static int _free_subrequest_data(fr_dlist_head_t *head) +{ + request_data_t *rd = NULL, *prev; + + while ((rd = fr_dlist_next(head, rd))) { + prev = fr_dlist_remove(head, rd); + talloc_free(rd); + rd = prev; + } + + return 0; +} + +/** Store persistable data from a subrequest in its parent + * + * @param[in] request The child request to retrieve state from. + * @param[in] unique_ptr A parent may have multiple subrequests spawned + * by different modules. This identifies the module + * or other facility that spawned the subrequest. + * @param[in] unique_int Further identification. + */ +void request_data_store_in_parent(REQUEST *request, void *unique_ptr, int unique_int) +{ + fr_dlist_head_t *head; + + if (request_data_by_persistance_count(request, true) == 0) return; + + MEM(head = talloc_zero(request->parent->state_ctx, fr_dlist_head_t)); + fr_dlist_talloc_init(head, request_data_t, list); + talloc_set_destructor(head, _free_subrequest_data); + + /* + * Pull everything out of the child, + * add it to our temporary list head... + */ + request_data_by_persistance(head, request, true); + + /* + * ...add that to the parent request under + * the specified unique identifiers. + */ + request_data_add(request->parent, unique_ptr, unique_int, head, true, false, true); +} + +/** Restore subrequest data from a parent request + * + * @param[in] request The child request to restore state to. + * @param[in] unique_ptr A parent may have multiple subrequests spawned + * by different modules. This identifies the module + * or other facility that spawned the subrequest. + * @param[in] unique_int Further identification. + */ +void request_data_restore_to_child(REQUEST *request, void *unique_ptr, int unique_int) +{ + fr_dlist_head_t *head; + + rad_assert(!request->state_ctx); + request->state_ctx = request->parent->state_ctx; /* Use top level state ctx */ + + head = request_data_get(request->parent, unique_ptr, unique_int); + if (!head) return; + + request_data_restore(request, head); + talloc_free(head); +} + #ifdef WITH_VERIFY_PTR /* * Verify a packet. diff --git a/src/lib/server/request.h b/src/lib/server/request.h index df7a7c3a26a..d858394ca34 100644 --- a/src/lib/server/request.h +++ b/src/lib/server/request.h @@ -207,8 +207,14 @@ void *request_data_reference(REQUEST *request, void const *unique_ptr, int uniq int request_data_by_persistance(fr_dlist_head_t *out, REQUEST *request, bool persist); +int request_data_by_persistance_count(REQUEST *request, bool persist); + void request_data_restore(REQUEST *request, fr_dlist_head_t *in); +void request_data_store_in_parent(REQUEST *request, void *unique_ptr, int unique_int); + +void request_data_restore_to_child(REQUEST *request, void *unique_ptr, int unique_int); + #ifdef WITH_VERIFY_PTR void request_verify(char const *file, int line, REQUEST const *request); /* only for special debug builds */ diff --git a/src/lib/server/state.c b/src/lib/server/state.c index 95f9f7f4c69..67448cf0875 100644 --- a/src/lib/server/state.c +++ b/src/lib/server/state.c @@ -107,7 +107,7 @@ typedef struct { //!< tied to the lifetime of the request progression. VALUE_PAIR *vps; //!< session-state VALUE_PAIRs, parented by ctx. - fr_dlist_head_t data; //!< Persistable request data, also parented ctx. + fr_dlist_head_t data; //!< Persistable request data, also parented by ctx. REQUEST *thawed; //!< The request that thawed this entry. } fr_state_entry_t; @@ -716,6 +716,51 @@ int fr_request_to_state(fr_state_tree_t *state, REQUEST *request) return 0; } +/** Store subrequest's session-state list and persistable request data in its parent + * + * @param[in] request The child request to retrieve state from. + * @param[in] unique_ptr A parent may have multiple subrequests spawned + * by different modules. This identifies the module + * or other facility that spawned the subrequest. + * @param[in] unique_int Further identification. + */ +void fr_state_store_in_parent(REQUEST *request, void *unique_ptr, int unique_int) +{ + rad_assert(request->parent); + + RDEBUG3("Subrequest state - saved to %s", request->parent->name); + + /* + * Shove this into the child to make + * it easier to store/restore the + * whole lot... + */ + request_data_add(request, (void *)fr_state_store_in_parent, 0, request->state, true, false, true); + request->state = NULL; + + request_data_store_in_parent(request, unique_ptr, unique_int); +} + +/** Restore subrequest data from a parent request + * + * @param[in] request The child request to restore state to. + * @param[in] unique_ptr A parent may have multiple subrequests spawned + * by different modules. This identifies the module + * or other facility that spawned the subrequest. + * @param[in] unique_int Further identification. + */ +void fr_state_restore_to_child(REQUEST *request, void *unique_ptr, int unique_int) +{ + RDEBUG3("Subrequest state - restored from %s", request->parent->name); + + request_data_restore_to_child(request, unique_ptr, unique_int); + + /* + * Get the state vps back + */ + request->state = request_data_get(request, (void *)fr_state_store_in_parent, 0); +} + /** Return number of entries created * */ diff --git a/src/lib/server/state.h b/src/lib/server/state.h index 4f76fab49a0..d2d5eaa9e1b 100644 --- a/src/lib/server/state.h +++ b/src/lib/server/state.h @@ -38,10 +38,13 @@ typedef struct fr_state_tree_t fr_state_tree_t; fr_state_tree_t *fr_state_tree_init(TALLOC_CTX *ctx, fr_dict_attr_t const *da, bool thread_safe, uint32_t max_sessions, uint32_t timeout, uint8_t server_id); -void fr_state_discard(fr_state_tree_t *state, REQUEST *request); +void fr_state_discard(fr_state_tree_t *state, REQUEST *request); -void fr_state_to_request(fr_state_tree_t *state, REQUEST *request); -int fr_request_to_state(fr_state_tree_t *state, REQUEST *request); +void fr_state_to_request(fr_state_tree_t *state, REQUEST *request); +int fr_request_to_state(fr_state_tree_t *state, REQUEST *request); + +void fr_state_store_in_parent(REQUEST *request, void *unique_ptr, int unique_int); +void fr_state_restore_to_child(REQUEST *request, void *unique_ptr, int unique_int); /* * Stats