[asterisk-commits] rmudgett: branch rmudgett/parking r330367 - /team/rmudgett/parking/main/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sat Jul 30 18:16:36 CDT 2011
Author: rmudgett
Date: Sat Jul 30 18:16:32 2011
New Revision: 330367
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=330367
Log:
Add parking lot dialplan usage map construction/destruction code.
Modified:
team/rmudgett/parking/main/features.c
Modified: team/rmudgett/parking/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/main/features.c?view=diff&rev=330367&r1=330366&r2=330367
==============================================================================
--- team/rmudgett/parking/main/features.c (original)
+++ team/rmudgett/parking/main/features.c Sat Jul 30 18:16:32 2011
@@ -385,6 +385,47 @@
static char pickup_ext[AST_MAX_EXTENSION]; /*!< Call pickup extension */
+/*! Parking lot access ramp dialplan usage entry. */
+struct parking_dp_ramp {
+ /*! Next node in the parking lot spaces dialplan list. */
+ AST_LIST_ENTRY(parking_dp_ramp) node;
+ /*! Parking lot access extension */
+ char exten[1];
+};
+
+/*! Parking lot dialplan access ramp map */
+AST_LIST_HEAD_NOLOCK(parking_dp_ramp_map, parking_dp_ramp);
+
+/*! Parking lot spaces dialplan usage entry. */
+struct parking_dp_spaces {
+ /*! Next node in the parking lot spaces dialplan list. */
+ AST_LIST_ENTRY(parking_dp_spaces) node;
+ /*! First parking space */
+ int start;
+ /*! Last parking space */
+ int stop;
+};
+
+/*! Parking lot dialplan context space map */
+AST_LIST_HEAD_NOLOCK(parking_dp_space_map, parking_dp_spaces);
+
+/*! Parking lot context dialplan usage entry. */
+struct parking_dp_context {
+ /*! Next node in the parking lot contexts dialplan list. */
+ AST_LIST_ENTRY(parking_dp_context) node;
+ /*! Parking access extensions defined in this context. */
+ struct parking_dp_ramp_map access_extens;
+ /*! Parking spaces defined in this context. */
+ struct parking_dp_space_map spaces;
+ /*! Parking hints defined in this context. */
+ struct parking_dp_space_map hints;
+ /*! Parking lot context name */
+ char context[1];
+};
+
+/*! Parking lot dialplan usage map. */
+AST_LIST_HEAD_NOLOCK(parking_dp_map, parking_dp_context);
+
/*!
* \brief Description of one parked call, added to a list while active, then removed.
* The list belongs to a parkinglot.
@@ -486,7 +527,7 @@
AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings;
};
-/*! \brief The list of parking lots configured. Always at least one - the default parking lot */
+/*! \brief The configured parking lots container. Always at least one - the default parking lot */
static struct ao2_container *parkinglots;
/*!
@@ -5406,6 +5447,367 @@
return 0;
}
+/*!
+ * \internal
+ * \brief Destroy the given dialplan usage context.
+ *
+ * \param doomed Parking lot usage context to destroy.
+ *
+ * \return Nothing
+ */
+static void destroy_dialplan_usage_context(struct parking_dp_context *doomed)
+{
+ struct parking_dp_ramp *ramp;
+ struct parking_dp_spaces *spaces;
+
+ while ((ramp = AST_LIST_REMOVE_HEAD(&doomed->access_extens, node))) {
+ ast_free(ramp);
+ }
+ while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->spaces, node))) {
+ ast_free(spaces);
+ }
+ while ((spaces = AST_LIST_REMOVE_HEAD(&doomed->hints, node))) {
+ ast_free(spaces);
+ }
+ ast_free(doomed);
+}
+
+/*!
+ * \internal
+ * \brief Destroy the given dialplan usage map.
+ *
+ * \param doomed Parking lot usage map to destroy.
+ *
+ * \return Nothing
+ */
+static void destroy_dialplan_usage_map(struct parking_dp_map *doomed)
+{
+ struct parking_dp_context *item;
+
+ while ((item = AST_LIST_REMOVE_HEAD(doomed, node))) {
+ destroy_dialplan_usage_context(item);
+ }
+}
+
+/*!
+ * \internal
+ * \brief Create a new parking lot ramp dialplan usage node.
+ *
+ * \param exten Parking lot access ramp extension.
+ * \param lot Parking lot supplying reference data.
+ *
+ * \retval New usage ramp node on success.
+ * \retval NULL on error.
+ */
+static struct parking_dp_ramp *build_dialplan_useage_ramp(const char *exten, struct ast_parkinglot *lot)
+{
+ struct parking_dp_ramp *ramp_node;
+
+ ramp_node = ast_calloc(1, sizeof(*ramp_node) + strlen(exten));
+ if (!ramp_node) {
+ return NULL;
+ }
+ strcpy(ramp_node->exten, exten);
+ return ramp_node;
+}
+
+/*!
+ * \internal
+ * \brief Add parking lot access ramp to the context ramp usage map.
+ *
+ * \param ramp_map Current parking lot context ramp usage map.
+ * \param exten Parking lot access ramp extension to add.
+ * \param lot Parking lot supplying reference data.
+ *
+ * \retval 0 on success. The ramp_map is updated.
+ * \retval -1 on failure.
+ */
+static int usage_context_add_ramp(struct parking_dp_ramp_map *ramp_map, const char *exten, struct ast_parkinglot *lot)
+{
+ struct parking_dp_ramp *cur_ramp;
+ struct parking_dp_ramp *new_ramp;
+ int cmp;
+
+ AST_LIST_TRAVERSE_SAFE_BEGIN(ramp_map, cur_ramp, node) {
+ cmp = strcmp(exten, cur_ramp->exten);
+ if (cmp > 0) {
+ /* The parking lot ramp goes after this node. */
+ continue;
+ }
+ if (cmp == 0) {
+ /* The ramp is already in the map. */
+ return 0;
+ }
+ /* The new parking lot ramp goes before this node. */
+ new_ramp = build_dialplan_useage_ramp(exten, lot);
+ if (!new_ramp) {
+ return -1;
+ }
+ AST_LIST_INSERT_BEFORE_CURRENT(new_ramp, node);
+ return 0;
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+
+ /* New parking lot access ramp goes on the end. */
+ new_ramp = build_dialplan_useage_ramp(exten, lot);
+ if (!new_ramp) {
+ return -1;
+ }
+ AST_LIST_INSERT_TAIL(ramp_map, new_ramp, node);
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Create a new parking lot spaces dialplan usage node.
+ *
+ * \param start First parking lot space to add.
+ * \param stop Last parking lot space to add.
+ * \param lot Parking lot supplying reference data.
+ *
+ * \retval New usage ramp node on success.
+ * \retval NULL on error.
+ */
+static struct parking_dp_spaces *build_dialplan_useage_spaces(int start, int stop, struct ast_parkinglot *lot)
+{
+ struct parking_dp_spaces *spaces_node;
+
+ spaces_node = ast_calloc(1, sizeof(*spaces_node));
+ if (!spaces_node) {
+ return NULL;
+ }
+ spaces_node->start = start;
+ spaces_node->stop = stop;
+ return spaces_node;
+}
+
+/*!
+ * \internal
+ * \brief Add parking lot spaces to the context space usage map.
+ *
+ * \param space_map Current parking lot context space usage map.
+ * \param start First parking lot space to add.
+ * \param stop Last parking lot space to add.
+ * \param lot Parking lot supplying reference data.
+ *
+ * \retval 0 on success. The space_map is updated.
+ * \retval -1 on failure.
+ */
+static int usage_context_add_spaces(struct parking_dp_space_map *space_map, int start, int stop, struct ast_parkinglot *lot)
+{
+ struct parking_dp_spaces *cur_node;
+ struct parking_dp_spaces *expand_node;
+ struct parking_dp_spaces *new_node;
+
+ expand_node = NULL;
+ AST_LIST_TRAVERSE_SAFE_BEGIN(space_map, cur_node, node) {
+ /* NOTE: stop + 1 to combine immediately adjacent nodes into one. */
+ if (expand_node) {
+ /* The previous node is expanding to possibly eat following nodes. */
+ if (expand_node->stop + 1 < cur_node->start) {
+ /* Current node is completely after expanding node. */
+ return 0;
+ }
+
+ /* Current node is eaten by the expanding node. */
+ if (expand_node->stop < cur_node->stop) {
+ expand_node->stop = cur_node->stop;
+ }
+ AST_LIST_REMOVE_CURRENT(node);
+ ast_free(cur_node);
+ continue;
+ }
+
+ if (cur_node->stop + 1 < start) {
+ /* New range is completely after current node. */
+ continue;
+ }
+ if (stop + 1 < cur_node->start) {
+ /* New range is completely before current node. */
+ new_node = build_dialplan_useage_spaces(start, stop, lot);
+ if (!new_node) {
+ return -1;
+ }
+ AST_LIST_INSERT_BEFORE_CURRENT(new_node, node);
+ return 0;
+ }
+
+ /* Current node range overlaps or is immediately adjacent to new range. */
+ if (start < cur_node->start) {
+ /* Expand the current node in the front. */
+ cur_node->start = start;
+ }
+ if (stop <= cur_node->stop) {
+ /* Current node is not expanding in the rear. */
+ return 0;
+ }
+ cur_node->stop = stop;
+ expand_node = cur_node;
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+
+ if (expand_node) {
+ /*
+ * The previous node expanded and either ate all following nodes
+ * or it was the last node.
+ */
+ return 0;
+ }
+
+ /* New range goes on the end. */
+ new_node = build_dialplan_useage_spaces(start, stop, lot);
+ if (!new_node) {
+ return -1;
+ }
+ AST_LIST_INSERT_TAIL(space_map, new_node, node);
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Add parking lot spaces to the context dialplan usage node.
+ *
+ * \param ctx_node Usage node to add parking lot spaces.
+ * \param lot Parking lot to add data to ctx_node.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int dialplan_usage_add_parkinglot_data(struct parking_dp_context *ctx_node, struct ast_parkinglot *lot)
+{
+ if (usage_context_add_ramp(&ctx_node->access_extens, lot->cfg.parkext, lot)) {
+ return -1;
+ }
+ if (usage_context_add_spaces(&ctx_node->spaces, lot->cfg.parking_start,
+ lot->cfg.parking_stop, lot)) {
+ return -1;
+ }
+ if (lot->cfg.parkaddhints
+ && usage_context_add_spaces(&ctx_node->hints, lot->cfg.parking_start,
+ lot->cfg.parking_stop, lot)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Create a new parking lot context dialplan usage node.
+ *
+ * \param lot Parking lot to create a new dialplan usage from.
+ *
+ * \retval New usage context node on success.
+ * \retval NULL on error.
+ */
+static struct parking_dp_context *build_dialplan_useage_context(struct ast_parkinglot *lot)
+{
+ struct parking_dp_context *ctx_node;
+
+ ctx_node = ast_calloc(1, sizeof(*ctx_node) + strlen(lot->cfg.parking_con));
+ if (!ctx_node) {
+ return NULL;
+ }
+ if (dialplan_usage_add_parkinglot_data(ctx_node, lot)) {
+ destroy_dialplan_usage_context(ctx_node);
+ return NULL;
+ }
+ strcpy(ctx_node->context, lot->cfg.parking_con);
+ return ctx_node;
+}
+
+/*!
+ * \internal
+ * \brief Add the given parking lot dialplan usage to the dialplan usage map.
+ *
+ * \param usage_map Parking lot usage map to add the given parking lot.
+ * \param lot Parking lot to add dialplan usage.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int dialplan_usage_add_parkinglot(struct parking_dp_map *usage_map, struct ast_parkinglot *lot)
+{
+ struct parking_dp_context *cur_ctx;
+ struct parking_dp_context *new_ctx;
+ int cmp;
+
+ AST_LIST_TRAVERSE_SAFE_BEGIN(usage_map, cur_ctx, node) {
+ cmp = strcmp(lot->cfg.parking_con, cur_ctx->context);
+ if (cmp > 0) {
+ /* The parking lot context goes after this node. */
+ continue;
+ }
+ if (cmp == 0) {
+ /* This is the node we will add parking lot spaces to the map. */
+ return dialplan_usage_add_parkinglot_data(cur_ctx, lot);
+ }
+ /* The new parking lot context goes before this node. */
+ new_ctx = build_dialplan_useage_context(lot);
+ if (!new_ctx) {
+ return -1;
+ }
+ AST_LIST_INSERT_BEFORE_CURRENT(new_ctx, node);
+ return 0;
+ }
+ AST_LIST_TRAVERSE_SAFE_END;
+
+ /* New parking lot context goes on the end. */
+ new_ctx = build_dialplan_useage_context(lot);
+ if (!new_ctx) {
+ return -1;
+ }
+ AST_LIST_INSERT_TAIL(usage_map, new_ctx, node);
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Build the dialplan usage map of the current parking lot container.
+ *
+ * \param usage_map Parking lot usage map. Must already be initialized.
+ *
+ * \retval 0 on success. The usage_map is filled in.
+ * \retval -1 on failure. Built usage_map is incomplete.
+ */
+static int build_dialplan_useage_map(struct parking_dp_map *usage_map)
+{
+ int status = 0;
+ struct ao2_iterator iter;
+ struct ast_parkinglot *curlot;
+
+ /* For all parking lots */
+ iter = ao2_iterator_init(parkinglots, 0);
+ for (; (curlot = ao2_iterator_next(&iter)); ao2_ref(curlot, -1)) {
+ /* Add the parking lot to the map. */
+ if (dialplan_usage_add_parkinglot(usage_map, curlot)) {
+ ao2_ref(curlot, -1);
+ status = -1;
+ break;
+ }
+ }
+ ao2_iterator_destroy(&iter);
+
+ return status;
+}
+
+/*!
+ * \internal
+ * \brief Remove unused parking lot dialplan items.
+ *
+ * \param old_map Before configuration reload dialplan usage map.
+ * \param new_map After configuration reload dialplan usage map.
+ *
+ * \details
+ * Remove dialplan items that were in the old map but not in the
+ * new map.
+ *
+ * \return Nothing
+ */
+static void remove_dead_dialplan_useage(struct parking_dp_map *old_map, struct parking_dp_map *new_map)
+{
+ /*! \todo BUGBUG remove_dead_dialplan_useage() not written */
+}
+
static int parkinglot_markall_cb(void *obj, void *arg, int flags)
{
struct ast_parkinglot *parkinglot = obj;
@@ -5442,6 +5844,8 @@
struct ast_flags config_flags = { 0 };
#endif
struct ast_config *cfg;
+ struct parking_dp_map old_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
+ struct parking_dp_map new_usage_map = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
/* We are reloading now and have already determined if we will force the reload. */
force_reload_load = 0;
@@ -5469,7 +5873,14 @@
return 0;
}
-/* BUGBUG build old contexts and extens usage list. */
+ /* Save current parking lot dialplan needs. */
+ if (build_dialplan_useage_map(&old_usage_map)) {
+ destroy_dialplan_usage_map(&old_usage_map);
+
+ /* Allow reloading later to see if conditions have improved. */
+ force_reload_load = 1;
+ return -1;
+ }
ao2_t_callback(parkinglots, OBJ_NODATA, parkinglot_markall_cb, NULL,
"callback to mark all parking lots");
@@ -5478,10 +5889,23 @@
ao2_t_callback(parkinglots, OBJ_NODATA | OBJ_UNLINK, parkinglot_is_marked_cb, NULL,
"callback to remove marked parking lots");
-/* BUGBUG build new contexts and extens usage list. */
-/* BUGBUG Remove dead contexts and extens */
-/* BUGBUG Destroy old and new contexts and extens usage lists. */
-/* BUGBUG Populate dialplan with new contexts and extens. */
+ /* Save updated parking lot dialplan needs. */
+ if (build_dialplan_useage_map(&new_usage_map)) {
+ /*
+ * Yuck, if this failure caused any parking lot dialplan items
+ * to be lost, they will likely remain lost until Asterisk is
+ * restarted.
+ */
+ destroy_dialplan_usage_map(&old_usage_map);
+ destroy_dialplan_usage_map(&new_usage_map);
+ return -1;
+ }
+
+ /* Remove no longer needed parking lot dialplan usage. */
+ remove_dead_dialplan_useage(&old_usage_map, &new_usage_map);
+
+ destroy_dialplan_usage_map(&old_usage_map);
+ destroy_dialplan_usage_map(&new_usage_map);
return 0;
}
More information about the asterisk-commits
mailing list