[asterisk-commits] mjordan: branch mjordan/cdrs-of-doom r386791 - in /team/mjordan/cdrs-of-doom:...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sun Apr 28 21:47:37 CDT 2013
Author: mjordan
Date: Sun Apr 28 21:47:32 2013
New Revision: 386791
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386791
Log:
Fix merge conflicts, update with more bridging stuff
Dial into a multi-party conference is the last thing to work
through. At least for the 'basic' scenarios.
Modified:
team/mjordan/cdrs-of-doom/include/asterisk/config_options.h
team/mjordan/cdrs-of-doom/main/bridging.c
team/mjordan/cdrs-of-doom/main/cdr.c
team/mjordan/cdrs-of-doom/main/config_options.c
team/mjordan/cdrs-of-doom/res/res_stasis.c
team/mjordan/cdrs-of-doom/tests/test_cdr.c
Modified: team/mjordan/cdrs-of-doom/include/asterisk/config_options.h
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/include/asterisk/config_options.h?view=diff&rev=386791&r1=386790&r2=386791
==============================================================================
--- team/mjordan/cdrs-of-doom/include/asterisk/config_options.h (original)
+++ team/mjordan/cdrs-of-doom/include/asterisk/config_options.h Sun Apr 28 21:47:32 2013
@@ -146,10 +146,11 @@
/*! \brief The representation of a single configuration file to be processed */
struct aco_file {
- const char *filename; /*!< \brief The filename to be processed */
- const char *alias; /*!< \brief An alias filename to be tried if 'filename' cannot be found */
- const char **preload; /*!< \brief A null-terminated oredered array of categories to be loaded first */
- struct aco_type *types[]; /*!< The list of types for this config. Required. Use a sentinel! */
+ const char *filename; /*!< The filename to be processed */
+ const char *alias; /*!< An alias filename to be tried if 'filename' cannot be found */
+ const char **preload; /*!< A null-terminated ordered array of categories to be loaded first */
+ const char *skip_category; /*!< A regular expression of categories to skip in the file. Use when a file is processed by multiple modules */
+ struct aco_type *types[]; /*!< The list of types for this config. Required. Use a sentinel! */
};
struct aco_info {
Modified: team/mjordan/cdrs-of-doom/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/bridging.c?view=diff&rev=386791&r1=386790&r2=386791
==============================================================================
--- team/mjordan/cdrs-of-doom/main/bridging.c (original)
+++ team/mjordan/cdrs-of-doom/main/bridging.c Sun Apr 28 21:47:32 2013
@@ -3625,7 +3625,7 @@
struct ast_bridge_channel *peer_bridge_channel)
{
struct ast_bridge *dst_bridge = NULL;
- struct ast_bridge *src_bridge = NULL;
+ /* struct ast_bridge *src_bridge = NULL; */
struct ast_bridge_channel *dst_bridge_channel = NULL;
struct ast_bridge_channel *src_bridge_channel = NULL;
int peer_priority;
@@ -3645,13 +3645,13 @@
if (chan_bridge->num_channels == 2
&& chan_priority <= peer_priority) {
dst_bridge = peer_bridge;
- src_bridge = chan_bridge;
+ /* src_bridge = chan_bridge; */
dst_bridge_channel = peer_bridge_channel;
src_bridge_channel = chan_bridge_channel;
} else if (peer_bridge->num_channels == 2
&& peer_priority <= chan_priority) {
dst_bridge = chan_bridge;
- src_bridge = peer_bridge;
+ /* src_bridge = peer_bridge; */
dst_bridge_channel = chan_bridge_channel;
src_bridge_channel = peer_bridge_channel;
}
@@ -3660,7 +3660,7 @@
&& !ast_test_flag(&peer_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_TO)) {
/* Can swap optimize only one way. */
dst_bridge = peer_bridge;
- src_bridge = chan_bridge;
+ /* src_bridge = chan_bridge; */
dst_bridge_channel = peer_bridge_channel;
src_bridge_channel = chan_bridge_channel;
} else if (peer_bridge->num_channels == 2
@@ -3668,7 +3668,7 @@
&& !ast_test_flag(&chan_bridge->feature_flags, AST_BRIDGE_FLAG_SWAP_INHIBIT_TO)) {
/* Can swap optimize only one way. */
dst_bridge = chan_bridge;
- src_bridge = peer_bridge;
+ /* src_bridge = peer_bridge; */
dst_bridge_channel = chan_bridge_channel;
src_bridge_channel = peer_bridge_channel;
}
Modified: team/mjordan/cdrs-of-doom/main/cdr.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/cdr.c?view=diff&rev=386791&r1=386790&r2=386791
==============================================================================
--- team/mjordan/cdrs-of-doom/main/cdr.c (original)
+++ team/mjordan/cdrs-of-doom/main/cdr.c Sun Apr 28 21:47:32 2013
@@ -221,6 +221,7 @@
/*! \brief The file definition */
static struct aco_file module_file_conf = {
.filename = "cdr.conf", /*< The name of the config file */
+ .skip_category = "(^csv$|^custom$|^manager$|^odbc$|^pgsql$|^radius$|^sqlite$|^tds$|^mysql$)",
.types = ACO_TYPES(&general_option), /*< The type to process */
};
@@ -307,10 +308,14 @@
static struct ao2_container *active_cdrs_by_bridge;
/*! \brief Message router for stasis messages regarding channel state */
-static struct stasis_message_router *stasis_channel_router;
-
-/*! \brief Message router for stasis messages regarding bridge state */
-static struct stasis_message_router *stasis_bridge_router;
+static struct stasis_message_router *stasis_router;
+
+static struct stasis_subscription *bridge_subscription;
+
+static struct stasis_subscription *channel_subscription;
+
+/*! \brief The parent topic for all topics we want to aggregate for CDRs */
+static struct stasis_topic *cdr_topic;
struct cdr_object;
@@ -321,17 +326,33 @@
struct cdr_object_fn_table {
/*! Name of the subclass */
const char *name;
+
/*! An initialization function. This will be called automatically when a
* \ref cdr_object is switched to this type in
* \ref cdr_object_transition_state
+ *
+ * \param cdr The \ref cdr_object that was just transitioned
*/
void (* const init_function)(struct cdr_object *cdr);
- /*! Process a Party A update for the \ref cdr_object */
- void (* const process_party_a_update)(struct cdr_object *cdr,
+
+ /*! Process a Party A update for the \ref cdr_object
+ *
+ * \param cdr The \ref cdr_object to process the update
+ * \param snapshot The snapshot for the CDR's Party A
+ * \retval 0 the CDR handled the update or ignored it
+ * \retval 1 the CDR is finalized and a new one should be made to handle it
+ */
+ int (* const process_party_a_update)(struct cdr_object *cdr,
struct ast_channel_snapshot *snapshot);
- /*! Process a Party B update for the \ref cdr_object */
+
+ /*! Process a Party B update for the \ref cdr_object
+ *
+ * \param cdr The \ref cdr_object to process the update
+ * \param snapshot The snapshot for the CDR's Party B
+ */
void (* const process_party_b_update)(struct cdr_object *cdr,
struct ast_channel_snapshot *snapshot);
+
/*! Process the beginning of a dial. A dial message implies one of two
* things:
* The \ref cdr_object's Party A has been originated
@@ -341,8 +362,7 @@
*/
int (* const process_dial_begin)(struct cdr_object *cdr,
struct ast_channel_snapshot *caller,
- struct ast_channel_snapshot *peer,
- const char *dial_status);
+ struct ast_channel_snapshot *peer);
int (* const process_dial_end)(struct cdr_object *cdr,
struct ast_channel_snapshot *caller,
struct ast_channel_snapshot *peer,
@@ -356,56 +376,86 @@
};
AST_MUTEX_DEFINE_STATIC(cdr_sched_lock);
-static void base_process_party_a_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static int base_process_bridge_leave_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
static void single_state_init_function(struct cdr_object *cdr);
-static void single_state_process_party_b_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
+static void single_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
static int single_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
struct cdr_object_fn_table single_state_fn_table = {
.name = "Single",
.init_function = single_state_init_function,
- .process_party_a_update = base_process_party_a_update,
- .process_party_b_update = single_state_process_party_b_update,
+ .process_party_a_update = base_process_party_a,
+ .process_party_b_update = single_state_process_party_b,
.process_dial_begin = single_state_process_dial_begin,
.process_dial_end = base_process_dial_end,
.process_bridge_enter = single_state_process_bridge_enter,
- .process_bridge_leave = base_process_bridge_leave_message,
+ .process_bridge_leave = base_process_bridge_leave,
};
-static void dial_state_process_party_b_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
+static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
+static int dial_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
struct cdr_object_fn_table dial_state_fn_table = {
.name = "Dial",
- .process_party_a_update = base_process_party_a_update,
- .process_party_b_update = dial_state_process_party_b_update,
+ .process_party_a_update = base_process_party_a,
+ .process_party_b_update = dial_state_process_party_b,
.process_dial_begin = dial_state_process_dial_begin,
.process_dial_end = dial_state_process_dial_end,
- .process_bridge_leave = base_process_bridge_leave_message,
+ .process_bridge_enter = dial_state_process_bridge_enter,
+ .process_bridge_leave = base_process_bridge_leave,
};
-static void bridge_state_init_function(struct cdr_object *cdr);
-static void bridge_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
struct cdr_object_fn_table bridge_state_fn_table = {
.name = "Bridged",
- .init_function = bridge_state_init_function,
- .process_party_a_update = base_process_party_a_update,
- .process_bridge_leave = bridge_process_bridge_leave,
+ .process_party_a_update = base_process_party_a,
+ .process_party_b_update = bridge_state_process_party_b,
+ .process_bridge_leave = bridge_state_process_bridge_leave,
};
+static void pending_state_init_function(struct cdr_object *cdr);
+static int pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+static int pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
+static int pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+
+struct cdr_object_fn_table bridged_pending_state_fn_table = {
+ .name = "Pending",
+ .init_function = pending_state_init_function,
+ .process_party_a_update = pending_state_process_party_a,
+ .process_dial_begin = pending_state_process_dial_begin,
+ .process_dial_end = base_process_dial_end,
+ .process_bridge_enter = pending_state_process_bridge_enter,
+ .process_bridge_leave = base_process_bridge_leave,
+};
+
+static int dialed_pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer);
+static int dialed_pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+
+struct cdr_object_fn_table dialed_pending_state_fn_table = {
+ .name = "DialedPending",
+ .process_party_a_update = dialed_pending_state_process_party_a,
+ .process_dial_begin = dialed_pending_state_process_dial_begin,
+ .process_dial_end = base_process_dial_end,
+ .process_bridge_enter = dialed_pending_state_process_bridge_enter,
+ .process_bridge_leave = base_process_bridge_leave,
+};
+
static void finalized_state_init_function(struct cdr_object *cdr);
-static void finalized_state_process_party_a_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
struct cdr_object_fn_table finalized_state_fn_table = {
.name = "Finalized",
.init_function = finalized_state_init_function,
- .process_party_a_update = finalized_state_process_party_a_update,
+ .process_party_a_update = finalized_state_process_party_a,
};
/*! \brief A wrapper object around a snapshot.
@@ -514,8 +564,14 @@
{
struct cdr_object *left = obj;
struct cdr_object *right = arg;
+ struct cdr_object *it_cdr;
const char *match = (flags & OBJ_KEY) ? arg : right->bridge;
- return strcasecmp(left->bridge, match) ? 0 : (CMP_MATCH);
+ for (it_cdr = left; it_cdr; it_cdr = it_cdr->next) {
+ if (!strcasecmp(it_cdr->bridge, match)) {
+ return CMP_MATCH;
+ }
+ }
+ return 0;
}
static void cdr_object_dtor(void *obj)
@@ -851,7 +907,7 @@
/* BASE METHOD IMPLEMENTATIONS */
-static void base_process_party_a_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+static int base_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
@@ -862,13 +918,15 @@
cdr_object_check_party_a_answer(cdr);
cdr_object_check_party_a_hangup(cdr);
-}
-
-static int base_process_bridge_leave_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
+
+ return 0;
+}
+
+static int base_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
{
/* Assume we shouldn't get a bridge leave message for ourselves */
ast_assert(strcmp(channel->name, cdr->party_a.snapshot->name) != 0);
- return 0;
+ return 1;
}
static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
@@ -887,7 +945,7 @@
cdr_object_check_party_a_answer(cdr);
}
-static void single_state_process_party_b_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+static void single_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
{
/* This should never happen! */
ast_assert(cdr->party_b.snapshot == NULL);
@@ -895,7 +953,7 @@
return;
}
-static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
+static int single_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
@@ -1026,22 +1084,25 @@
cdr_object_finalize(cdr);
}
-static void finalized_state_process_party_a_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+static int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
{
if (ast_test_flag(&cdr->party_a.snapshot->flags, AST_FLAG_ZOMBIE)) {
cdr_object_finalize(cdr);
}
+
+ return 1;
}
/* DIAL STATE */
-static void dial_state_process_party_b_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+static void dial_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
{
ast_assert(snapshot != NULL);
- if (cdr->party_b.snapshot && !strcmp(cdr->party_b.snapshot->name, snapshot->name)) {
- cdr_object_swap_snapshot(&cdr->party_b, snapshot);
- }
+ if (!cdr->party_b.snapshot || strcmp(cdr->party_b.snapshot->name, snapshot->name)) {
+ return;
+ }
+ cdr_object_swap_snapshot(&cdr->party_b, snapshot);
/* If party B hangs up, finalize this CDR */
if (ast_test_flag(&cdr->party_b.snapshot->flags, AST_FLAG_ZOMBIE)) {
@@ -1049,9 +1110,18 @@
}
}
-static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
-{
- RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
+static int dial_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
+{
+ /* Don't process a begin dial here. A party A already in the dial state will
+ * who receives a dial begin for something else will be handled by the
+ * message router callback and will add a new CDR for the party A */
+ return 1;
+}
+
+static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
+{
+ RAII_VAR(struct module_config *, mod_cfg,
+ ao2_global_obj_ref(module_configs), ao2_cleanup);
struct ast_channel_snapshot *party_a;
if (caller) {
@@ -1062,12 +1132,6 @@
ast_assert(!strcmp(cdr->party_a.snapshot->name, party_a->name));
cdr_object_swap_snapshot(&cdr->party_a, party_a);
- if (ast_strlen_zero(dial_status)) {
- /* If this isn't a dial end, don't process it here. A begin dial for
- * a party A already in the dial state will be handled by the message
- * router callback and add a new CDR for the party A */
- return 1;
- }
if (cdr->party_b.snapshot) {
if (strcmp(cdr->party_b.snapshot->name, peer->name)) {
/* Not the status for this CDR - defer back to the message router */
@@ -1078,7 +1142,9 @@
/* Set the disposition based on the dial string. */
if (!strcmp(dial_status, "ANSWER")) {
- /* TODO: if ANSWER, do NOTHING? */
+ cdr->disposition = AST_CDR_ANSWERED;
+ /* Switch to dial pending to wait and see what the caller does */
+ cdr_object_transition_state(cdr, &dialed_pending_state_fn_table);
return 0;
} else if (!strcmp(dial_status, "BUSY")) {
cdr->disposition = AST_CDR_BUSY;
@@ -1093,28 +1159,164 @@
return 0;
}
-static int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
-{
-
+static int dial_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
+{
+ struct ao2_iterator *it_cdrs;
+ char *bridge_id = ast_strdupa(bridge->uniqueid);
+ struct cdr_object *cand_cdr_master;
+ int success = 1;
+
+ ast_string_field_set(cdr, bridge, bridge->uniqueid);
+
+ /* Get parties in the bridge */
+ it_cdrs = ao2_callback(active_cdrs_by_bridge, OBJ_MULTIPLE | OBJ_KEY,
+ cdr_object_bridge_cmp_fn, bridge_id);
+ if (!it_cdrs) {
+ /* No one in the bridge yet! */
+ cdr_object_transition_state(cdr, &bridge_state_fn_table);
+ return 0;
+ }
+
+ while ((cand_cdr_master = ao2_iterator_next(it_cdrs))) {
+ struct cdr_object *cand_cdr;
+
+ ao2_lock(cand_cdr_master);
+ for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
+ /* Skip any records that are not in a bridge or in this bridge.
+ * I'm not sure how that would happen, but it pays to be careful. */
+ if (cand_cdr->fn_table != &bridge_state_fn_table ||
+ strcmp(cdr->bridge, cand_cdr->bridge)) {
+ continue;
+ }
+
+ /* Skip any records that aren't our Party B */
+ if (strcmp(cdr->party_b.snapshot->name, cand_cdr->party_a.snapshot->name)) {
+ continue;
+ }
+
+ cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
+ /* If they have a Party B, they joined up with someone else as their
+ * Party A. Don't finalize them as they're active. Otherwise, we
+ * have stolen them so they need to be finalized.
+ */
+ if (!cand_cdr->party_b.snapshot) {
+ cdr_object_finalize(cand_cdr);
+ }
+ success = 0;
+ break;
+ }
+ ao2_unlock(cand_cdr_master);
+ ao2_t_ref(cand_cdr_master, -1, "Drop iterator reference");
+ }
+ ao2_iterator_destroy(it_cdrs);
+
+ /* We always transition state, even if we didn't get a peer */
+ cdr_object_transition_state(cdr, &bridge_state_fn_table);
+
+ /* Success implies that we have a Party B */
+ return success;
}
/* BRIDGE STATE */
-static void bridge_state_init_function(struct cdr_object *cdr)
-{
-
-}
-
-static int base_process_bridge_leave_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
+static void bridge_state_process_party_b(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+{
+ if (!cdr->party_b.snapshot || strcmp(cdr->party_b.snapshot->name, snapshot->name)) {
+ return;
+ }
+ cdr_object_swap_snapshot(&cdr->party_b, snapshot);
+
+ /* If party B hangs up, finalize this CDR */
+ if (ast_test_flag(&cdr->party_b.snapshot->flags, AST_FLAG_ZOMBIE)) {
+ cdr_object_transition_state(cdr, &finalized_state_fn_table);
+ }
+}
+
+static int bridge_state_process_bridge_leave(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
{
if (strcmp(cdr->bridge, bridge->uniqueid)) {
+ return 1;
+ }
+ cdr_object_transition_state(cdr, &finalized_state_fn_table);
+
+ return 0;
+}
+
+/* PENDING STATE */
+
+static void pending_state_init_function(struct cdr_object *cdr)
+{
+ ast_cdr_set_property(cdr->name, AST_CDR_FLAG_DISABLE);
+}
+
+static int pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+{
+ if (ast_test_flag(&snapshot->flags, AST_FLAG_ZOMBIE)) {
return 0;
}
+ /* If we get a CEP change, we're executing dialplan. Switch to single.
+ * Otherwise, ignore.
+ */
+ if (!strcmp(snapshot->context, cdr->party_a.snapshot->context)
+ && !strcmp(snapshot->exten, cdr->party_a.snapshot->exten)
+ && snapshot->priority == cdr->party_a.snapshot->priority) {
+ return 0;
+ }
+
+ cdr_object_transition_state(cdr, &single_state_fn_table);
+ ast_cdr_clear_property(cdr->name, AST_CDR_FLAG_DISABLE);
+ cdr->fn_table->process_party_a_update(cdr, snapshot);
+ return 0;
+}
+
+static int pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
+{
+ cdr_object_transition_state(cdr, &single_state_fn_table);
+ ast_cdr_clear_property(cdr->name, AST_CDR_FLAG_DISABLE);
+ return cdr->fn_table->process_dial_begin(cdr, caller, peer);
+}
+
+static int pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
+{
+ cdr_object_transition_state(cdr, &single_state_fn_table);
+ ast_cdr_clear_property(cdr->name, AST_CDR_FLAG_DISABLE);
+ return cdr->fn_table->process_bridge_enter(cdr, bridge, channel);
+}
+
+
+/* DIALED PENDING STATE */
+
+static int dialed_pending_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
+{
+ /* If we get a CEP change, we're executing dialplan. Finalize ourselves
+ * and ask the handler to make a new CDR if needed.
+ */
+ if (strcmp(snapshot->context, cdr->party_a.snapshot->context)
+ || strcmp(snapshot->exten, cdr->party_a.snapshot->exten)
+ || snapshot->priority != cdr->party_a.snapshot->priority) {
+ cdr_object_transition_state(cdr, &finalized_state_fn_table);
+ return 1;
+ }
+ base_process_party_a(cdr, snapshot);
+ return 0;
+}
+
+static int dialed_pending_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
+{
+ cdr_object_transition_state(cdr, &dial_state_fn_table);
+ return cdr->fn_table->process_bridge_enter(cdr, bridge, channel);
+}
+
+static int dialed_pending_state_process_dial_begin(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer)
+{
+ struct cdr_object *new_cdr;
+
cdr_object_transition_state(cdr, &finalized_state_fn_table);
-
- return 0;
+ new_cdr = cdr_object_create_and_append(cdr);
+ cdr_object_transition_state(cdr, &single_state_fn_table);
+ return new_cdr->fn_table->process_dial_begin(cdr, caller, peer);
}
@@ -1185,20 +1387,26 @@
cdr, party_a->name, party_b ? party_b->name : "(none)");
ao2_lock(cdr);
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
- if (it_cdr->fn_table->process_dial_begin) {
- res &= it_cdr->fn_table->process_dial_begin(it_cdr, party_a, party_b, dial_status);
- }
- }
-
- /* If no CDR handled the dial message, make a new one */
- if (res) {
+ if (ast_strlen_zero(dial_status)) {
+ if (it_cdr->fn_table->process_dial_begin) {
+ res &= it_cdr->fn_table->process_dial_begin(it_cdr, party_a, party_b);
+ }
+ } else {
+ if (it_cdr->fn_table->process_dial_end) {
+ it_cdr->fn_table->process_dial_end(it_cdr, party_a, party_b, dial_status);
+ }
+ }
+ }
+
+ /* If no CDR handled a dial begin message, make a new one */
+ if (res && ast_strlen_zero(dial_status)) {
struct cdr_object *new_cdr;
new_cdr = cdr_object_create_and_append(cdr);
if (!new_cdr) {
return;
}
- new_cdr->fn_table->process_dial_begin(new_cdr, party_a, party_b, dial_status);
+ new_cdr->fn_table->process_dial_begin(new_cdr, party_a, party_b);
}
ao2_unlock(cdr);
}
@@ -1267,13 +1475,20 @@
if (cdr) {
ao2_lock(cdr);
if (new_snapshot) {
+ int all_reject = 1;
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
if (it_cdr->fn_table->process_party_a_update) {
CDR_DEBUG(mod_cfg, "%p - processing new channel snapshot %s\n", it_cdr, new_snapshot->name);
- it_cdr->fn_table->process_party_a_update(it_cdr, new_snapshot);
+ all_reject &= it_cdr->fn_table->process_party_a_update(it_cdr, new_snapshot);
}
}
+ if (all_reject && !ast_test_flag(&new_snapshot->flags, AST_FLAG_ZOMBIE)) {
+ struct cdr_object *new_cdr;
+ new_cdr = cdr_object_create_and_append(cdr);
+ new_cdr->fn_table->process_party_a_update(new_cdr, new_snapshot);
+ }
} else {
+ CDR_DEBUG(mod_cfg, "%p - beginning finalize/dispatch for %s\n", cdr, old_snapshot->name);
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
cdr_object_finalize(it_cdr);
}
@@ -1297,20 +1512,44 @@
static void handle_bridge_leave_message(struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
{
+ RAII_VAR(struct module_config *, mod_cfg,
+ ao2_global_obj_ref(module_configs), ao2_cleanup);
RAII_VAR(struct cdr_object *, cdr,
ao2_find(active_cdrs_by_channel, channel->name, OBJ_KEY),
ao2_cleanup);
struct cdr_object *it_cdr;
-
- ast_assert(cdr != NULL);
+ struct cdr_object *pending_cdr;
+ int left_bridge = 0;
+
+ if (!cdr) {
+ return;
+ }
ao2_lock(cdr);
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
- if (it_cdr->fn_table->process_bridge_leave) {
- it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel);
- }
- }
+ if (!it_cdr->fn_table->process_bridge_leave) {
+ continue;
+ }
+ CDR_DEBUG(mod_cfg, "%p - Processing Bridge Leave for %s\n",
+ it_cdr, channel->name);
+ if (!it_cdr->fn_table->process_bridge_leave(it_cdr, bridge, channel)) {
+ ast_string_field_set(it_cdr, bridge, "");
+ left_bridge = 1;
+ }
+ }
+ if (!left_bridge) {
+ ao2_unlock(cdr);
+ return;
+ }
+
+ ao2_unlink(active_cdrs_by_bridge, cdr);
+
+ /* Create a new pending record. If the channel decides to do something else,
+ * the pending record will handle it - otherwise, if gets dropped.
+ */
+ pending_cdr = cdr_object_create_and_append(cdr);
+ cdr_object_transition_state(pending_cdr, &bridged_pending_state_fn_table);
ao2_unlock(cdr);
}
@@ -1408,6 +1647,7 @@
}
ao2_cleanup(bcand);
}
+ ao2_unlock(cand_cdr_master);
}
ao2_iterator_destroy(it_cdrs);
@@ -1478,7 +1718,7 @@
* add ourselves directly as the Party B, or if we need a new CDR.
*/
if (bcand->cdr->party_a.snapshot == bcand->candidate) {
- if (bcand->cdr->party_b.snapshot) {
+ if (bcand->cdr->party_b.snapshot && strcmp(bcand->cdr->party_b.snapshot->name, cdr->party_a.snapshot->name)) {
new_cdr = cdr_object_create_and_append(bcand->cdr);
cdr_object_snapshot_copy(&new_cdr->party_b, &cdr->party_a);
ast_string_field_set(new_cdr, bridge, cdr->bridge);
@@ -1548,19 +1788,24 @@
struct cdr_object *it_cdr;
struct cdr_object *handled_cdr = NULL;
- ast_assert(cdr != NULL);
+ if (!cdr) {
+ ast_debug(1, "No CDR for channel %s\n", channel->name);
+ return;
+ }
ao2_lock(cdr);
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
if (it_cdr->fn_table->process_party_a_update) {
- CDR_DEBUG(mod_cfg, "%p - updating Party A\n", it_cdr);
+ CDR_DEBUG(mod_cfg, "%p - updating Party A %s snapshot\n", it_cdr,
+ channel->name);
it_cdr->fn_table->process_party_a_update(it_cdr, channel);
}
/* Notify all states that they have entered a bridge */
if (it_cdr->fn_table->process_bridge_enter) {
- CDR_DEBUG(mod_cfg, "%p - processing bridge enter\n", it_cdr);
+ CDR_DEBUG(mod_cfg, "%p - Processing bridge enter for %s\n", it_cdr,
+ channel->name);
res &= it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
if (!res && !handled_cdr) {
handled_cdr = it_cdr;
@@ -2776,7 +3021,12 @@
ast_free(batch);
batch = NULL;
+ /* ao2_ref(stasis_router, -1);
+ ao2_ref(bridge_subscription, -1);
+ ao2_ref(channel_subscription, -1);
+ ao2_ref(cdr_topic, -1);*/
ao2_ref(active_cdrs_by_channel, -1);
+ ao2_ref(active_cdrs_by_bridge, -1);
}
static void cdr_enable_batch_mode(struct ast_cdr_config *config)
@@ -2820,18 +3070,26 @@
return -1;
}
- stasis_channel_router = stasis_message_router_create(stasis_caching_get_topic(ast_channel_topic_all_cached()));
- if (!stasis_channel_router) {
+ cdr_topic = stasis_topic_create("cdr_engine");
+ if (!cdr_topic) {
return -1;
}
- stasis_message_router_add(stasis_channel_router, stasis_cache_update_type(), handle_channel_cache_message, NULL);
- stasis_message_router_add(stasis_channel_router, ast_channel_dial_type(), handle_dial_message, NULL);
-
- stasis_bridge_router = stasis_message_router_create(stasis_caching_get_topic(ast_bridge_topic_all_cached()));
- if (!stasis_bridge_router) {
+
+ channel_subscription = stasis_forward_all(stasis_caching_get_topic(ast_channel_topic_all_cached()), cdr_topic);
+ if (!channel_subscription) {
return -1;
}
- stasis_message_router_add(stasis_bridge_router, ast_bridge_blob_type(), handle_bridge_message, NULL);
+ bridge_subscription = stasis_forward_all(stasis_caching_get_topic(ast_bridge_topic_all_cached()), cdr_topic);
+ if (!bridge_subscription) {
+ return -1;
+ }
+ stasis_router = stasis_message_router_create(cdr_topic);
+ if (!stasis_router) {
+ return -1;
+ }
+ stasis_message_router_add(stasis_router, stasis_cache_update_type(), handle_channel_cache_message, NULL);
+ stasis_message_router_add(stasis_router, ast_channel_dial_type(), handle_dial_message, NULL);
+ stasis_message_router_add(stasis_router, ast_bridge_blob_type(), handle_bridge_message, NULL);
sched = ast_sched_context_create();
if (!sched) {
Modified: team/mjordan/cdrs-of-doom/main/config_options.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/config_options.c?view=diff&rev=386791&r1=386790&r2=386791
==============================================================================
--- team/mjordan/cdrs-of-doom/main/config_options.c (original)
+++ team/mjordan/cdrs-of-doom/main/config_options.c Sun Apr 28 21:47:32 2013
@@ -430,10 +430,21 @@
* We do not grab a reference to these objects, as the info already holds references to them. This
* pointer is just a convenience. Do not actually store it somewhere. */
void **field;
+ regex_t *regex_skip;
/* Skip preloaded categories if we aren't preloading */
if (!preload && is_preload(file, cat)) {
return 0;
+ }
+
+ /* Skip the category if we've been told to ignore it */
+ if (!ast_strlen_zero(file->skip_category)) {
+ regex_skip = build_regex(file->skip_category);
+ if (!regexec(regex_skip, cat, 0, NULL, 0)) {
+ ast_free(regex_skip);
+ return 0;
+ }
+ ast_free(regex_skip);
}
/* Find aco_type by category, if not found it is an error */
Modified: team/mjordan/cdrs-of-doom/res/res_stasis.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/res/res_stasis.c?view=diff&rev=386791&r1=386790&r2=386791
==============================================================================
--- team/mjordan/cdrs-of-doom/res/res_stasis.c (original)
+++ team/mjordan/cdrs-of-doom/res/res_stasis.c Sun Apr 28 21:47:32 2013
@@ -323,7 +323,7 @@
struct ast_channel *chan, void *data)
{
ast_debug(3, "%s: Answering", control->channel_id);
- return __ast_answer(chan, 0, 1) == 0 ? &OK : &FAIL;
+ return __ast_answer(chan, 0) == 0 ? &OK : &FAIL;
}
int stasis_app_control_answer(struct stasis_app_control *control)
Modified: team/mjordan/cdrs-of-doom/tests/test_cdr.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/tests/test_cdr.c?view=diff&rev=386791&r1=386790&r2=386791
==============================================================================
--- team/mjordan/cdrs-of-doom/tests/test_cdr.c (original)
+++ team/mjordan/cdrs-of-doom/tests/test_cdr.c Sun Apr 28 21:47:32 2013
@@ -216,6 +216,15 @@
/*! \brief Alice's Caller ID */
#define ALICE_CALLERID { .id.name.str = "Alice", .id.name.valid = 1, .id.number.str = "100", .id.number.valid = 1, }
+/*! \brief Bob's Caller ID */
+#define BOB_CALLERID { .id.name.str = "Bob", .id.name.valid = 1, .id.number.str = "200", .id.number.valid = 1, }
+
+/*! \brief Charlie's Caller ID */
+#define CHARLIE_CALLERID { .id.name.str = "Charlie", .id.name.valid = 1, .id.number.str = "300", .id.number.valid = 1, }
+
+/*! \brief David's Caller ID */
+#define DAVID_CALLERID { .id.name.str = "David", .id.name.valid = 1, .id.number.str = "400", .id.number.valid = 1, }
+
/*! \brief Copy the linkedid and uniqueid from a channel to an expected CDR */
#define COPY_IDS(channel_var, expected_record) do { \
ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
@@ -223,7 +232,7 @@
} while (0)
/*! \brief Create a \ref test_cdr_chan_tech for Alice, and set the expected
- * CDR records (if available) to her linkedid and uniqueid. */
+ * CDR records' linkedid and uniqueid. */
#define CREATE_ALICE_CHANNEL(channel_var, caller_id, expected_record) do { \
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
ast_channel_set_caller((channel_var), (caller_id), NULL); \
@@ -231,8 +240,38 @@
ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
} while (0)
+/*! \brief Create a \ref test_cdr_chan_tech for Bob, and set the expected
+ * CDR records' linkedid and uniqueid. */
+#define CREATE_BOB_CHANNEL(channel_var, caller_id, expected_record) do { \
+ (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, "200", "Bob", "200", "200", "default", NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
+ ast_channel_set_caller((channel_var), (caller_id), NULL); \
+ ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
+ ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
+ } while (0)
+
+/*! \brief Create a \ref test_cdr_chan_tech for Charlie, and set the expected
+ * CDR records' linkedid and uniqueid. */
+#define CREATE_CHARLIE_CHANNEL(channel_var, caller_id, expected_record) do { \
+ (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, "300", "Charlie", "300", "300", "default", NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
+ ast_channel_set_caller((channel_var), (caller_id), NULL); \
+ ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
+ ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
+ } while (0)
+
+/*! \brief Create a \ref test_cdr_chan_tech for Charlie, and set the expected
+ * CDR records' linkedid and uniqueid. */
+#define CREATE_DAVID_CHANNEL(channel_var, caller_id, expected_record) do { \
+ (channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, "400", "David", "400", "400", "default", NULL, 0, CHANNEL_TECH_NAME "/David"); \
+ ast_channel_set_caller((channel_var), (caller_id), NULL); \
+ ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
+ ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
+ } while (0)
+
/*! \brief Emulate a channel entering into an application */
-#define EMULATE_APP_DATA(channel, application, data) do { \
+#define EMULATE_APP_DATA(channel, priority, application, data) do { \
+ if ((priority) > 0) { \
+ ast_channel_priority_set((channel), (priority)); \
+ } \
ast_channel_appl_set((channel), (application)); \
ast_channel_data_set((channel), (data)); \
publish_channel_snapshot((channel)); \
@@ -402,7 +441,7 @@
CREATE_ALICE_CHANNEL(chan, &caller, &expected);
/* Channel enters wait */
- EMULATE_APP_DATA(chan, "Wait", "1");
+ EMULATE_APP_DATA(chan, 1, "Wait", "1");
/* And hangs up */
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
@@ -418,6 +457,11 @@
RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
ao2_cleanup);
+ struct ast_party_caller caller = {
+ .id.name.str = "",
+ .id.name.valid = 1,
+ .id.number.str = "",
+ .id.number.valid = 1, };
struct ast_cdr expected = {
.clid = "\"\" <>",
.dst = "s",
@@ -446,12 +490,12 @@
SWAP_CONFIG(config, unanswered_cdr_config);
- CREATE_ALICE_CHANNEL(chan, NULL, &expected);
+ CREATE_ALICE_CHANNEL(chan, &caller, &expected);
ast_channel_exten_set(chan, "s");
ast_channel_context_set(chan, "default");
ast_set_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED);
- EMULATE_APP_DATA(chan, "AppDial", "(Outgoing Line)");
+ EMULATE_APP_DATA(chan, 0, "AppDial", "(Outgoing Line)");
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
result = verify_mock_cdr_record(test, &expected, 1);
@@ -497,14 +541,9 @@
SWAP_CONFIG(config, debug_cdr_config);
CREATE_ALICE_CHANNEL(chan, &caller, &expected);
- /* Channel enters Answer app */
- ast_channel_priority_set(chan, 1);
- EMULATE_APP_DATA(chan, "Answer", "");
+ EMULATE_APP_DATA(chan, 1, "Answer", "");
ast_setstate(chan, AST_STATE_UP);
-
- /* Channel enters the VoiceMailMain app */
- ast_channel_priority_set(chan, 2);
- EMULATE_APP_DATA(chan, "VoiceMailMain", "1");
+ EMULATE_APP_DATA(chan, 2, "VoiceMailMain", "1");
/* And then it hangs up */
[... 1009 lines stripped ...]
More information about the asterisk-commits
mailing list