return pl;
}
+/** Initialise fields in an fr_pair_t without assigning a da
+ *
+ * @note Internal use by the allocation functions only.
+ */
+static inline CC_HINT(always_inline) void pair_init_null(fr_pair_t *vp)
+{
+ fr_dlist_entry_init(&vp->order_entry);
+
+ /*
+ * Legacy cruft
+ */
+ vp->op = T_OP_EQ;
+ vp->type = VT_NONE;
+}
+
/** Dynamically allocate a new attribute with no #fr_dict_attr_t assigned
*
* This is not the function you're looking for (unless you're binding
fr_strerror_printf("Out of memory");
return NULL;
}
-
- fr_dlist_entry_init(&vp->order_entry);
-
talloc_set_destructor(vp, _fr_pair_free);
- /*
- * Legacy cruft
- */
- vp->op = T_OP_EQ;
- vp->type = VT_NONE;
+ pair_init_null(vp);
return vp;
}
* This is intended to allocate root attributes for requests.
* These roots are special in that they do not necessarily own
* the child attributes and _MUST NOT_ free them when they
- * themselves are freed.
+ * themselves are freed. The children are allocated in special
+ * ctxs which may be moved between session state entries and
+ * requests, or may belong to a parent request.
*
* @param[in] ctx to allocate the pair root in.
* @param[in] da The root attribute.
}
#endif
+ return vp;
+}
+
+/** Continue initialising an fr_pair_t assigning a da
+ *
+ * @note Internal use by the pair allocation functions only.
+ */
+static inline CC_HINT(always_inline) void pair_init_from_da(fr_pair_t *vp, fr_dict_attr_t const *da)
+{
/*
- * Legacy cruft
+ * If we get passed an unknown da, we need to ensure that
+ * it's parented by "vp".
*/
- vp->op = T_OP_EQ;
- vp->type = VT_NONE;
+ if (da->flags.is_unknown) {
+ fr_dict_attr_t const *unknown;
- return vp;
+ unknown = fr_dict_unknown_afrom_da(vp, da);
+ da = unknown;
+ }
+
+ /*
+ * Use the 'da' to initialize more fields.
+ */
+ vp->da = da;
+ fr_value_box_init(&vp->data, da->type, da, false);
+
+ switch (da->type) {
+ case FR_TYPE_STRUCTURAL:
+ fr_pair_list_init(&vp->vp_group);
+ break;
+ default:
+ break;
+ }
}
/** Dynamically allocate a new attribute and assign a #fr_dict_attr_t
*
* @param[in] ctx for allocated memory, usually a pointer to a #fr_radius_packet_t
* @param[in] da Specifies the dictionary attribute to build the #fr_pair_t from.
+ * If unknown, will be duplicated, with the memory being bound to
+ * the pair.
* @return
* - A new #fr_pair_t.
* - NULL if an error occurred.
return NULL;
}
- /*
- * If we get passed an unknown da, we need to ensure that
- * it's parented by "vp".
- */
- if (da->flags.is_unknown) {
- fr_dict_attr_t const *unknown;
+ pair_init_from_da(vp, da);
- unknown = fr_dict_unknown_afrom_da(vp, da);
- da = unknown;
- }
+ return vp;
+}
+
+/** Allocate a pooled object that can hold a fr_pair_t any unknown attributes and value buffer
+ *
+ * @param[in] ctx to allocate the pooled object in.
+ * @param[in] da If unknown, will be duplicated.
+ * @param[in] value_len The expected length of the buffer. +1 will be added if this
+ * if a FR_TYPE_STRING attribute.
+ */
+fr_pair_t *fr_pair_afrom_da_with_pool(TALLOC_CTX *ctx, fr_dict_attr_t const *da, size_t value_len)
+{
+ fr_pair_t *vp;
+
+ unsigned int headers = 1;
/*
- * Use the 'da' to initialize more fields.
+ * Dict attributes allocate extensions
+ * contiguously, so we only need one
+ * header even though there's a variable
+ * length name buff.
*/
- vp->da = da;
- fr_value_box_init(&vp->data, da->type, da, false);
+ if (da->flags.is_unknown) {
+ headers++;
+ value_len += talloc_array_length(da); /* accounts for all extensions */
+ }
switch (da->type) {
- case FR_TYPE_STRUCTURAL:
- fr_pair_list_init(&vp->vp_group);
+ case FR_TYPE_OCTETS:
+ headers++;
break;
- default:
+
+ case FR_TYPE_STRING:
+ headers++;
+ value_len++;
break;
+
+ default:
+ fr_strerror_printf("Pooled fr_pair_t can only be allocated for "
+ "'string' and 'octets' types not '%s'",
+ fr_table_str_by_value(fr_value_box_type_table, da->type, "<INVALID>"));
+ return NULL;
+
}
+ vp = talloc_zero_pooled_object(ctx, fr_pair_t, headers, value_len);
+ if (unlikely(!vp)) {
+ fr_strerror_printf("Out of memory");
+ return NULL;
+ }
+ talloc_set_destructor(vp, _fr_pair_free);
+
+ pair_init_null(vp);
+ pair_init_from_da(vp, da);
+
return vp;
}