[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