return request;
}
+/** Replace the session_state_ctx with a new one.
+ *
+ * NOTHING should rewrite request->session_state_ctx.
+ *
+ * It's now a pair, and is stored in request->pair_root.
+ * So it's wrong for anyone other than this function to play games with it.
+ */
+fr_pair_t *request_state_replace(request_t *request, fr_pair_t *state)
+{
+ fr_pair_t *old = request->session_state_ctx;
+
+ fr_assert(request->session_state_ctx != NULL);
+ fr_assert(request->session_state_ctx != state);
+
+ fr_pair_remove(&request->pair_root->children, old);
+
+ /*
+ * Save (or delete) the existing state, and re-initialize
+ * it with a brand new one.
+ */
+ if (!state) MEM(state = fr_pair_afrom_da(NULL, request_attr_state));
+
+ request->session_state_ctx = state;
+
+ fr_pair_append(&request->pair_root->children, state);
+
+ return old;
+}
+
/** Unlink a subrequest from its parent
*
* @note This should be used for requests in preparation for freeing them.
/*
* If fr_state_to_request was called, then the request
- * holds the state data, and we need to destroy it
+ * holds the existing state data. We need to destroy it,
* and return the request to the state it was in when
- * it was first alloced, just in case a user does something
- * stupid like add additional session-state attributes
+ * it was first allocated, just in case a user does something
+ * stupid like add more session-state attributes
* in one of the later sections.
*/
- TALLOC_FREE(request->session_state_ctx);
-
- MEM(request->session_state_ctx = fr_pair_afrom_da(NULL, request_attr_state));
+ talloc_free(request_state_replace(request, NULL));
RDEBUG3("%s - discarded", state->da->name);
int fr_state_to_request(fr_state_tree_t *state, request_t *request)
{
fr_state_entry_t *entry;
- TALLOC_CTX *old_ctx;
fr_pair_t *vp;
/*
RERROR("State entry has already been thawed by a request %"PRIu64, entry->thawed->number);
return -2;
}
- old_ctx = request->session_state_ctx; /* Store for later freeing */
+ /*
+ * Discard any existing session state, and replace it
+ * with the cached one.
+ */
fr_assert(entry->ctx);
+ talloc_free(request_state_replace(request, entry->ctx));
+ entry->ctx = NULL;
request->seq_start = entry->seq_start;
- request->session_state_ctx = entry->ctx;
/*
* Associate old state with the request
request_data_add(request, state, 0, entry, true, true, false);
request_data_restore(request, &entry->data);
- entry->ctx = NULL;
entry->thawed = request;
if (!fr_pair_list_empty(&request->session_state_pairs)) {
log_request_pair_list(L_DBG_LVL_2, request, NULL, &request->session_state_pairs, "&session-state.");
}
- /*
- * Free this outside of the mutex for less contention.
- */
- talloc_free(old_ctx);
-
RDEBUG3("%s - restored", state->da->name);
/*
fr_assert(request->session_state_ctx);
entry->seq_start = request->seq_start;
- entry->ctx = request->session_state_ctx;
+ entry->ctx = request_state_replace(request, NULL);
fr_dlist_move(&entry->data, &data);
PTHREAD_MUTEX_UNLOCK(&state->mutex);
- MEM(request->session_state_ctx = fr_pair_afrom_da(NULL, request_attr_state)); /* fixme - should use a pool */
-
RDEBUG3("%s - saved", state->da->name);
REQUEST_VERIFY(request);
request_data_list_init(&child_entry->data);
talloc_set_destructor(child_entry, _free_child_data);
- child_entry->ctx = child->session_state_ctx;
+ child_entry->ctx = request_state_replace(child, NULL);
/*
* Pull everything out of the child,
*/
request_data_talloc_add(request->parent, unique_ptr, unique_int,
state_child_entry_t, child_entry, true, false, true);
-
- /*
- * Ensure fr_state_restore_to_child
- * can be called again if it's actually
- * needed, by giving the child it's own
- * unique state_ctx again.
- */
- MEM(request->session_state_ctx = fr_pair_afrom_da(NULL, request_attr_state));
}
}