[asterisk-commits] mjordan: branch mjordan/cdrs-of-doom r386639 - in /team/mjordan/cdrs-of-doom:...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Apr 26 15:41:02 CDT 2013
Author: mjordan
Date: Fri Apr 26 15:40:59 2013
New Revision: 386639
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386639
Log:
General clean up, re-order initialization in asterisk
Most of this is just clean up, but we also have to make sure we
initialize the bridging layer before we initialize things that use it,
including CDRs.
Modified:
team/mjordan/cdrs-of-doom/main/asterisk.c
team/mjordan/cdrs-of-doom/main/cdr.c
team/mjordan/cdrs-of-doom/tests/test_cdr.c
Modified: team/mjordan/cdrs-of-doom/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/main/asterisk.c?view=diff&rev=386639&r1=386638&r2=386639
==============================================================================
--- team/mjordan/cdrs-of-doom/main/asterisk.c (original)
+++ team/mjordan/cdrs-of-doom/main/asterisk.c Fri Apr 26 15:40:59 2013
@@ -4225,6 +4225,21 @@
ast_http_init(); /* Start the HTTP server, if needed */
+ if (ast_indications_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
+ if (ast_features_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
+ if (ast_bridging_init()) {
+ printf("%s", term_quit());
+ exit(1);
+ }
+
if (ast_cdr_engine_init()) {
printf("%s", term_quit());
exit(1);
@@ -4259,21 +4274,6 @@
}
if (load_pbx()) {
- printf("%s", term_quit());
- exit(1);
- }
-
- if (ast_indications_init()) {
- printf("%s", term_quit());
- exit(1);
- }
-
- if (ast_features_init()) {
- printf("%s", term_quit());
- exit(1);
- }
-
- if (ast_bridging_init()) {
printf("%s", term_quit());
exit(1);
}
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=386639&r1=386638&r2=386639
==============================================================================
--- team/mjordan/cdrs-of-doom/main/cdr.c (original)
+++ team/mjordan/cdrs-of-doom/main/cdr.c Fri Apr 26 15:40:59 2013
@@ -198,11 +198,6 @@
ast_verb(1, (fmt), ##__VA_ARGS__); \
} } while (0)
-enum cdr_flag_internal {
- INTERNAL_CDR_FLAG_SKIP = AST_CDR_FLAG_LAST, /*< Set when we need to temporarily skip a CDR for some reason */
- INTERNAL_CDR_FLAG_FORKED = (INTERNAL_CDR_FLAG_SKIP << 1),
-};
-
/*! \brief The configuration settings for this module */
struct module_config {
struct ast_cdr_config *general; /*< CDR global settings */
@@ -267,28 +262,33 @@
return mod_cfg;
}
-struct ast_cdr_beitem {
+/*! \brief Registration object for CDR backends */
+struct cdr_beitem {
char name[20];
char desc[80];
ast_cdrbe be;
- AST_RWLIST_ENTRY(ast_cdr_beitem) list;
+ AST_RWLIST_ENTRY(cdr_beitem) list;
};
-static AST_RWLIST_HEAD_STATIC(be_list, ast_cdr_beitem);
-
-struct ast_cdr_batch_item {
+/*! \brief List of registered backends */
+static AST_RWLIST_HEAD_STATIC(be_list, cdr_beitem);
+
+/*! \brief Queued CDR waiting to be batched */
+struct cdr_batch_item {
struct ast_cdr *cdr;
- struct ast_cdr_batch_item *next;
+ struct cdr_batch_item *next;
};
-static struct ast_cdr_batch {
+/*! \brief The actual batch queue
+ * TODO: use a list */
+static struct cdr_batch {
int size;
- struct ast_cdr_batch_item *head;
- struct ast_cdr_batch_item *tail;
+ struct cdr_batch_item *head;
+ struct cdr_batch_item *tail;
} *batch = NULL;
-static int cdr_sequence = 0;
+static int global_cdr_sequence = 0;
static struct ast_sched_context *sched;
static int cdr_sched = -1;
@@ -300,7 +300,6 @@
AST_MUTEX_DEFINE_STATIC(cdr_pending_lock);
static ast_cond_t cdr_pending_cond;
-
/*! \brief A container of the active CDRs indexed by Party A channel name */
static struct ao2_container *active_cdrs_by_channel;
@@ -315,23 +314,55 @@
struct cdr_object;
+/*! \brief A virtual table used for \ref cdr_object.
+ * Note that all functions are optional - if a subclass does not need an
+ * implementation, it is safe to leave it NULL.
+ */
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
+ */
void (* const init_function)(struct cdr_object *cdr);
- void (* const process_party_a_update)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
- void (* const process_party_b_update)(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
- int (* const process_dial_message)(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
- int (* const process_bridge_enter)(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
- int (* const process_bridge_leave)(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel);
+ /*! Process a Party A update for the \ref cdr_object */
+ void (* const process_party_a_update)(struct cdr_object *cdr,
+ struct ast_channel_snapshot *snapshot);
+ /*! Process a Party B update for the \ref cdr_object */
+ 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
+ * The \ref cdr_object's Party A is dialing its Party B
+ * Functions should return 0 if the parties in the dial message are for this
+ * \ref cdr_object, any other value otherwise.
+ */
+ int (* const process_dial_begin)(struct cdr_object *cdr,
+ struct ast_channel_snapshot *caller,
+ struct ast_channel_snapshot *peer,
+ const char *dial_status);
+ int (* const process_dial_end)(struct cdr_object *cdr,
+ struct ast_channel_snapshot *caller,
+ struct ast_channel_snapshot *peer,
+ const char *dial_status);
+ int (* const process_bridge_enter)(struct cdr_object *cdr,
+ struct ast_bridge_snapshot *bridge,
+ struct ast_channel_snapshot *channel);
+ int (* const process_bridge_leave)(struct cdr_object *cdr,
+ struct ast_bridge_snapshot *bridge,
+ struct ast_channel_snapshot *channel);
};
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_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_message(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, const char *dial_status);
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 = {
@@ -339,33 +370,33 @@
.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_dial_message = single_state_process_dial_message,
+ .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,
};
static void dial_state_process_party_b_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
-static int dial_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
+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 int dial_state_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status);
struct cdr_object_fn_table dial_state_fn_table = {
.name = "Dial",
- .init_function = NULL,
.process_party_a_update = base_process_party_a_update,
.process_party_b_update = dial_state_process_party_b_update,
- .process_dial_message = dial_state_process_dial_message,
+ .process_dial_begin = dial_state_process_dial_begin,
+ .process_dial_end = dial_state_process_dial_end,
.process_bridge_leave = base_process_bridge_leave_message,
};
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);
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_party_b_update = NULL,
- .process_dial_message = NULL,
- .process_bridge_enter = NULL,
- .process_bridge_leave = NULL,
+ .process_bridge_leave = bridge_process_bridge_leave,
};
static void finalized_state_init_function(struct cdr_object *cdr);
@@ -375,12 +406,11 @@
.name = "Finalized",
.init_function = finalized_state_init_function,
.process_party_a_update = finalized_state_process_party_a_update,
- .process_party_b_update = NULL,
- .process_dial_message = NULL,
- .process_bridge_enter = NULL,
- .process_bridge_leave = NULL,
};
+/*! \brief A wrapper object around a snapshot.
+ * Fields that are mutable by the CDR engine are replicated here.
+ */
struct cdr_object_snapshot {
struct ast_channel_snapshot *snapshot; /*!< The channel snapshot */
char userfield[AST_MAX_USER_FIELD]; /*!< Userfield for the channel */
@@ -388,6 +418,7 @@
struct varshead variables; /*!< CDR variables for the channel */
};
+/*! \brief An in-memory representation of an active CDR */
struct cdr_object {
struct cdr_object_snapshot party_a;
struct cdr_object_snapshot party_b;
@@ -405,10 +436,10 @@
AST_STRING_FIELD(bridge); /*< The bridge the party A happens to be in. */
);
struct cdr_object *next; /*< The next CDR object in the chain */
- struct cdr_object *prev; /*< The previous CDR object in the chain */
struct cdr_object *last; /*< The last CDR object in the chain */
};
+/*! \brief Copy variables from one list to another */
static int copy_vars(struct varshead *to_list, struct varshead *from_list)
{
struct ast_var_t *variables, *newvariable = NULL;
@@ -529,7 +560,7 @@
ast_string_field_set(cdr, name, chan->name);
ast_string_field_set(cdr, linkedid, chan->linkedid);
cdr->disposition = AST_CDR_NULL;
- cdr->sequence = ast_atomic_fetchadd_int(&cdr_sequence, +1);
+ cdr->sequence = ast_atomic_fetchadd_int(&global_cdr_sequence, +1);
cdr->party_a.snapshot = chan;
ao2_ref(cdr->party_a.snapshot, +1);
@@ -541,7 +572,7 @@
return cdr;
}
-static struct cdr_object *cdr_object_create_and_append_cdr(struct cdr_object *cdr)
+static struct cdr_object *cdr_object_create_and_append(struct cdr_object *cdr)
{
struct cdr_object *new_cdr;
struct cdr_object *it_cdr;
@@ -563,46 +594,9 @@
}
it_cdr->last = new_cdr;
it_cdr->next = new_cdr;
- new_cdr->prev = it_cdr;
return new_cdr;
}
-
-/*static void cdr_object_remove_cdr(struct cdr_object *master, struct cdr_object *record)
-{
- struct cdr_object *it_cdr;
- struct cdr_object *prev = NULL;
- struct cdr_object *next = NULL;
-
- for (it_cdr = master; it_cdr; prev = it_cdr, it_cdr = it_cdr->next) {
- if (it_cdr != record) {
- continue;
- }
- if (it_cdr->next) {
- next = it_cdr->next;
- }
- if (it_cdr == master) {*/
- /* Remove root */
-/* ao2_unlink(active_cdrs_by_channel, master);
- if (!ast_strlen_zero(master->bridge)) {
- ao2_unlink(active_cdrs_by_bridge, master);
- }
- }
- it_cdr->next = NULL;
- it_cdr->last = NULL;
- if (next && prev) {
- prev->next = next;
- prev->last = next->last;
- }
- if (next && it_cdr == master) {
- ao2_link(active_cdrs_by_channel, next);
- if (!ast_strlen_zero(next->bridge)) {
- ao2_link(active_cdrs_by_bridge, next);
- }
- }
- ao2_ref(it_cdr, -1);
- }
-}*/
static struct ast_channel_snapshot *cdr_object_determine_party_a(struct ast_channel_snapshot *left, struct ast_channel_snapshot *right)
{
@@ -663,6 +657,7 @@
*/
if (ast_test_flag(&cdr->party_a.snapshot->flags, AST_FLAG_OUTGOING)
&& !ast_test_flag(&cdr->party_a.snapshot->flags, AST_FLAG_ORIGINATED)) {
+ cdr = cdr->next;
continue;
}
@@ -844,15 +839,17 @@
}
}
-static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old,
- struct ast_channel_snapshot *new)
-{
- if (old->snapshot) {
- ao2_t_ref(old->snapshot, -1, "Drop ref for swap");
- }
- ao2_t_ref(new, +1, "Bump ref for swap");
- old->snapshot = new;
-}
+static void cdr_object_swap_snapshot(struct cdr_object_snapshot *old_snapshot,
+ struct ast_channel_snapshot *new_snapshot)
+{
+ if (old_snapshot->snapshot) {
+ ao2_t_ref(old_snapshot->snapshot, -1, "Drop ref for swap");
+ }
+ ao2_t_ref(new_snapshot, +1, "Bump ref for swap");
+ old_snapshot->snapshot = new_snapshot;
+}
+
+/* BASE METHOD IMPLEMENTATIONS */
static void base_process_party_a_update(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot)
{
@@ -871,6 +868,13 @@
{
/* Assume we shouldn't get a bridge leave message for ourselves */
ast_assert(strcmp(channel->name, cdr->party_a.snapshot->name) != 0);
+ return 0;
+}
+
+static int base_process_dial_end(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
+{
+ /* We shouldn't get a dial end if we aren't in the dial state */
+ ast_assert(0);
return 0;
}
@@ -891,12 +895,9 @@
return;
}
-static int single_state_process_dial_message(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, const char *dial_status)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
-
- /* We shouldn't get a Dial end without first transitioning to a dial state */
- ast_assert(ast_strlen_zero(dial_status));
if (caller && !strcmp(cdr->party_a.snapshot->name, caller->name)) {
cdr_object_swap_snapshot(&cdr->party_a, caller);
@@ -916,16 +917,30 @@
return 0;
}
+/*!
+ * \brief Handle a comparison between our \ref cdr_object and a \ref cdr_object
+ * already in the bridge while in the Single state. The goal of this is to find
+ * a Party B for our CDR.
+ *
+ * \param cdr Our \ref cdr_object in the Single state
+ * \param cand_cdr The \ref cdr_object already in the Bridge state
+ *
+ * \retval 0 The cand_cdr had a Party A or Party B that we could use as our
+ * Party B
+ * \retval 1 No party in the cand_cdr could be used as our Party B
+ */
static int single_state_bridge_enter_comparison(struct cdr_object *cdr,
struct cdr_object *cand_cdr)
{
struct ast_channel_snapshot *party_a;
- party_a = cdr_object_determine_party_a(cdr->party_a.snapshot, cand_cdr->party_a.snapshot);
+ /* Try the candidate CDR's Party A first */
+ party_a = cdr_object_determine_party_a(cdr->party_a.snapshot,
+ cand_cdr->party_a.snapshot);
if (party_a == cdr->party_a.snapshot) {
cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
if (!cand_cdr->party_b.snapshot) {
- /* We just stole them - finalize the CDR. Note that this won't
+ /* We just stole them - finalize their CDR. Note that this won't
* transition their state, it just sets the end time and the
* disposition - if we need to re-activate them later, we can.
*/
@@ -934,11 +949,12 @@
return 0;
}
+ /* Try their Party B */
if (!cand_cdr->party_b.snapshot) {
return 1;
}
-
- party_a = cdr_object_determine_party_a(cdr->party_a.snapshot, cand_cdr->party_b.snapshot);
+ party_a = cdr_object_determine_party_a(cdr->party_a.snapshot,
+ cand_cdr->party_b.snapshot);
if (party_a == cdr->party_a.snapshot) {
cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
return 0;
@@ -972,12 +988,12 @@
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)) {
+ if (cand_cdr->fn_table != &bridge_state_fn_table ||
+ strcmp(cdr->bridge, cand_cdr->bridge)) {
continue;
}
if (single_state_bridge_enter_comparison(cdr, cand_cdr)) {
- /* Keep looking */
continue;
}
/* We successfully got a party B - break out */
@@ -985,7 +1001,7 @@
break;
}
ao2_unlock(cand_cdr_master);
- ao2_ref(cand_cdr_master, -1);
+ ao2_t_ref(cand_cdr_master, -1, "Drop iterator reference");
}
ao2_iterator_destroy(it_cdrs);
@@ -1033,7 +1049,7 @@
}
}
-static int dial_state_process_dial_message(struct cdr_object *cdr, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const char *dial_status)
+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);
struct ast_channel_snapshot *party_a;
@@ -1077,6 +1093,11 @@
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)
+{
+
+}
+
/* BRIDGE STATE */
@@ -1085,7 +1106,16 @@
}
-
+static int base_process_bridge_leave_message(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
+{
+ if (strcmp(cdr->bridge, bridge->uniqueid)) {
+ return 0;
+ }
+
+ cdr_object_transition_state(cdr, &finalized_state_fn_table);
+
+ return 0;
+}
@@ -1155,8 +1185,8 @@
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_message) {
- res &= it_cdr->fn_table->process_dial_message(it_cdr, party_a, party_b, dial_status);
+ if (it_cdr->fn_table->process_dial_begin) {
+ res &= it_cdr->fn_table->process_dial_begin(it_cdr, party_a, party_b, dial_status);
}
}
@@ -1164,12 +1194,13 @@
if (res) {
struct cdr_object *new_cdr;
- new_cdr = cdr_object_create_and_append_cdr(cdr);
+ new_cdr = cdr_object_create_and_append(cdr);
if (!new_cdr) {
return;
}
- new_cdr->fn_table->process_dial_message(new_cdr, party_a, party_b, dial_status);
- }
+ new_cdr->fn_table->process_dial_begin(new_cdr, party_a, party_b, dial_status);
+ }
+ ao2_unlock(cdr);
}
static int cdr_object_finalize_party_b(void *obj, void *arg, int flags)
@@ -1234,8 +1265,7 @@
if (!cdr) {
cdr = ao2_find(active_cdrs_by_channel, name, OBJ_KEY);
if (cdr) {
- SCOPED_AO2LOCK(lock, cdr);
-
+ ao2_lock(cdr);
if (new_snapshot) {
for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
if (it_cdr->fn_table->process_party_a_update) {
@@ -1250,6 +1280,7 @@
cdr_object_dispatch(cdr);
ao2_unlink(active_cdrs_by_channel, cdr);
}
+ ao2_unlock(cdr);
}
}
@@ -1266,7 +1297,22 @@
static void handle_bridge_leave_message(struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
{
-
+ 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);
+
+ 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);
+ }
+ }
+
+ ao2_unlock(cdr);
}
struct bridge_candidate {
@@ -1419,7 +1465,7 @@
party_a = cdr_object_determine_party_a(cdr->party_a.snapshot, bcand->candidate);
if (party_a == cdr->party_a.snapshot) {
- new_cdr = cdr_object_create_and_append_cdr(cdr);
+ new_cdr = cdr_object_create_and_append(cdr);
if (bcand->candidate == bcand->cdr->party_a.snapshot) {
cdr_object_snapshot_copy(&new_cdr->party_b, &bcand->cdr->party_a);
} else if (bcand->candidate == bcand->cdr->party_b.snapshot) {
@@ -1433,7 +1479,7 @@
*/
if (bcand->cdr->party_a.snapshot == bcand->candidate) {
if (bcand->cdr->party_b.snapshot) {
- new_cdr = cdr_object_create_and_append_cdr(bcand->cdr);
+ 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);
cdr_object_transition_state(new_cdr, &bridge_state_fn_table);
@@ -1446,8 +1492,14 @@
memset(&bcand->cdr->end, 0, sizeof(bcand->cdr->end));
}
} else {
+ /* Since we know that all channels in a bridge that have a Party A
+ * CDR in the bridge were added, if we are that channel's Party B
+ * then we have to find their current CDR, add ourselves to it, and
+ * add it to the CDRs in the bridge.
+ */
struct cdr_object *b_party = ao2_find(active_cdrs_by_channel, bcand->candidate->name, OBJ_KEY);
if (!b_party) {
+ /* Holy cow - no CDR? */
b_party = cdr_object_alloc(bcand->candidate);
cdr_object_transition_state(b_party, &bridge_state_fn_table);
cdr_object_snapshot_copy(&b_party->party_b, &cdr->party_a);
@@ -1457,7 +1509,7 @@
ao2_ref(b_party, -1);
return 0;
}
- new_cdr = cdr_object_create_and_append_cdr(b_party);
+ new_cdr = cdr_object_create_and_append(b_party);
cdr_object_transition_state(b_party, &bridge_state_fn_table);
cdr_object_snapshot_copy(&b_party->party_b, &cdr->party_a);
ast_string_field_set(b_party, bridge, cdr->bridge);
@@ -1485,12 +1537,13 @@
return;
}
-
static void handle_bridge_enter_message(struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
{
RAII_VAR(struct cdr_object *, cdr,
ao2_find(active_cdrs_by_channel, channel->name, OBJ_KEY),
ao2_cleanup);
+ RAII_VAR(struct module_config *, mod_cfg,
+ ao2_global_obj_ref(module_configs), ao2_cleanup);
int res = 1;
struct cdr_object *it_cdr;
struct cdr_object *handled_cdr = NULL;
@@ -1501,11 +1554,13 @@
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);
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);
res &= it_cdr->fn_table->process_bridge_enter(it_cdr, bridge, channel);
if (!res && !handled_cdr) {
handled_cdr = it_cdr;
@@ -1539,7 +1594,6 @@
static void handle_bridge_message(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message)
{
RAII_VAR(struct cdr_object *, cdr, NULL, ao2_cleanup);
- RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
struct ast_bridge_blob *update = stasis_message_data(message);
const char *type = ast_bridge_blob_json_type(update);
@@ -1550,6 +1604,8 @@
handle_bridge_leave_message(update->bridge, update->channel);
} else if (!strcmp(type, "enter")) {
handle_bridge_enter_message(update->bridge, update->channel);
+ } else {
+ ast_assert(0);
}
}
@@ -1587,7 +1643,7 @@
*/
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
{
- struct ast_cdr_beitem *i = NULL;
+ struct cdr_beitem *i = NULL;
if (!name)
return -1;
@@ -1622,7 +1678,7 @@
/*! unregister a CDR driver */
void ast_cdr_unregister(const char *name)
{
- struct ast_cdr_beitem *i = NULL;
+ struct cdr_beitem *i = NULL;
AST_RWLIST_WRLOCK(&be_list);
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
@@ -2170,7 +2226,7 @@
static void post_cdr(struct ast_cdr *cdr)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
- struct ast_cdr_beitem *i;
+ struct cdr_beitem *i;
for (; cdr ; cdr = cdr->next) {
/* For people, who don't want to see unanswered single-channel events */
@@ -2301,7 +2357,7 @@
/* Copy over the basic CDR information. The Party A information is
* copied over automatically as part of the append
*/
- new_cdr = cdr_object_create_and_append_cdr(cdr);
+ new_cdr = cdr_object_create_and_append(cdr);
if (!new_cdr) {
return -1;
}
@@ -2346,12 +2402,6 @@
}
cdr_object_transition_state(it_cdr, &finalized_state_fn_table);
}
- } else {
- /* Denote that this CDR is a fork of a previous, and the previous
- * is still active. Operations on CDRs will use this flag to force
- * this CDR record to mirror the state of the previous.
- */
- ast_set_flag(&new_cdr->flags, INTERNAL_CDR_FLAG_FORKED);
}
}
@@ -2380,8 +2430,8 @@
static void *do_batch_backend_process(void *data)
{
- struct ast_cdr_batch_item *processeditem;
- struct ast_cdr_batch_item *batchitem = data;
+ struct cdr_batch_item *processeditem;
+ struct cdr_batch_item *batchitem = data;
/* Push each CDR into storage mechanism(s) and free all the memory */
while (batchitem) {
@@ -2398,7 +2448,7 @@
void ast_cdr_submit_batch(int do_shutdown)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
- struct ast_cdr_batch_item *oldbatchitems = NULL;
+ struct cdr_batch_item *oldbatchitems = NULL;
pthread_t batch_post_thread = AST_PTHREADT_NULL;
/* if there's no batch, or no CDRs in the batch, then there's nothing to do */
@@ -2458,7 +2508,7 @@
void ast_cdr_detach(struct ast_cdr *cdr)
{
- struct ast_cdr_batch_item *newtail;
+ struct cdr_batch_item *newtail;
int curr;
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
int submit_batch = 0;
@@ -2574,7 +2624,7 @@
static char *handle_cli_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
- struct ast_cdr_beitem *beitem = NULL;
+ struct cdr_beitem *beitem = NULL;
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
int cnt = 0;
long nextbatchtime = 0;
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=386639&r1=386638&r2=386639
==============================================================================
--- team/mjordan/cdrs-of-doom/tests/test_cdr.c (original)
+++ team/mjordan/cdrs-of-doom/tests/test_cdr.c Fri Apr 26 15:40:59 2013
@@ -462,6 +462,8 @@
AST_TEST_DEFINE(test_cdr_single_party)
{
RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
@@ -492,7 +494,7 @@
case TEST_EXECUTE:
break;
}
-
+ SWAP_CONFIG(config, debug_cdr_config);
CREATE_ALICE_CHANNEL(chan, &caller, &expected);
/* Channel enters Answer app */
@@ -512,6 +514,131 @@
return result;
}
+AST_TEST_DEFINE(test_cdr_single_bridge)
+{
+ RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
+ struct timespec to_sleep = {1, 0};
+
+ struct ast_party_caller caller = ALICE_CALLERID;
+ struct ast_cdr expected = {
+ .clid = "\"Alice\" <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .lastapp = "Bridge",
+ .billsec = 1,
+ .amaflags = AST_AMA_DOCUMENTATION,
+ .disposition = AST_CDR_ANSWERED,
+ .accountcode = "100",
+ };
+ enum ast_test_result_state result = AST_TEST_NOT_RUN;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
+ info->summary = "Test cdrs for a single party entering/leaving a bridge";
+ info->description =
+ "Test the properties of a CDR for a call that is\n"
+ "answered, enters a bridge, and leaves it.\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+ 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", "");
+ ast_setstate(chan, AST_STATE_UP);
+ ast_channel_priority_set(chan, 2);
+ EMULATE_APP_DATA(chan, "Bridge", "");
+
+ bridge = ast_bridge_basic_new();
+ ast_test_validate(test, bridge != NULL);
+
+ ast_bridge_impart(bridge, chan, NULL, NULL, 0);
+
+ while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR));
+
+ ast_bridge_depart(chan);
+
+ /* And then it hangs up */
+ HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
+
+ result = verify_mock_cdr_record(test, &expected, 1);
+
+ return result;
+}
+
+AST_TEST_DEFINE(test_cdr_single_twoparty_bridge)
+{
+ RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
+ RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
+ ao2_cleanup);
+ struct timespec to_sleep = {1, 0};
+
+ struct ast_party_caller caller = ALICE_CALLERID;
+ struct ast_cdr expected = {
+ .clid = "\"Alice\" <100>",
+ .src = "100",
+ .dst = "100",
+ .dcontext = "default",
+ .channel = CHANNEL_TECH_NAME "/Alice",
+ .dstchannel = CHANNEL_TECH_NAME "/Bob",
+ .lastapp = "Bridge",
+ .billsec = 1,
+ .amaflags = AST_AMA_DOCUMENTATION,
+ .disposition = AST_CDR_ANSWERED,
+ .accountcode = "100",
+ };
+ enum ast_test_result_state result = AST_TEST_NOT_RUN;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = TEST_CATEGORY;
+ info->summary = "Test cdrs for a single party entering/leaving a bridge";
+ info->description =
+ "Test the properties of a CDR for a call that is\n"
+ "answered, enters a bridge, and leaves it.\n";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+ 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", "");
+ ast_setstate(chan, AST_STATE_UP);
+ ast_channel_priority_set(chan, 2);
+ EMULATE_APP_DATA(chan, "Bridge", "");
+
+ bridge = ast_bridge_basic_new();
+ ast_test_validate(test, bridge != NULL);
+
+ ast_bridge_impart(bridge, chan, NULL, NULL, 0);
+
+ while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR));
+
+ ast_bridge_depart(chan);
+
+ /* And then it hangs up */
+ HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL);
+
+ result = verify_mock_cdr_record(test, &expected, 1);
+
+ return result;
+}
+
AST_TEST_DEFINE(test_cdr_dial_unanswered)
{
RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
@@ -519,6 +646,7 @@
RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
ao2_cleanup);
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -551,7 +679,7 @@
SWAP_CONFIG(config, unanswered_cdr_config);
- CREATE_ALICE_CHANNEL(chan_caller, NULL, &expected);
+ CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
/* Channel enters Dial app */
ast_channel_priority_set(chan_caller, 1);
@@ -561,9 +689,6 @@
chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
EMULATE_APP_DATA(chan_callee, "AppDial", "(Outgoing Line)");
- /* TODO: come back and see if this worked
- * ast_channel_appl_set(chan_callee, "AppDial");
- ast_channel_data_set(chan_callee, "(Outgoing Line)");*/
/* Dial starts */
ast_channel_publish_dial(chan_caller, chan_callee, "Bob", NULL);
@@ -592,6 +717,7 @@
RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
ao2_cleanup);
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -624,7 +750,7 @@
SWAP_CONFIG(config, unanswered_cdr_config);
- CREATE_ALICE_CHANNEL(chan_caller, NULL, &expected);
+ CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
/* Channel enters Dial app */
ast_channel_appl_set(chan_caller, "Dial");
@@ -663,6 +789,7 @@
RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
ao2_cleanup);
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -695,7 +822,7 @@
SWAP_CONFIG(config, congestion_cdr_config);
- CREATE_ALICE_CHANNEL(chan_caller, NULL, &expected);
+ CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
/* Channel enters Dial app */
ast_channel_appl_set(chan_caller, "Dial");
@@ -734,6 +861,7 @@
RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
ao2_cleanup);
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -766,7 +894,7 @@
SWAP_CONFIG(config, unanswered_cdr_config);
- CREATE_ALICE_CHANNEL(chan_caller, NULL, &expected);
+ CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
/* Channel enters Dial app */
ast_channel_appl_set(chan_caller, "Dial");
@@ -805,6 +933,7 @@
RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
ao2_cleanup);
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -838,7 +967,7 @@
SWAP_CONFIG(config, unanswered_cdr_config);
- CREATE_ALICE_CHANNEL(chan_caller, NULL, &expected);
+ CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
/* Channel enters Dial app */
ast_channel_appl_set(chan_caller, "Dial");
@@ -878,6 +1007,7 @@
RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
ao2_cleanup);
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr bob_expected = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -946,7 +1076,7 @@
SWAP_CONFIG(config, congestion_cdr_config);
- CREATE_ALICE_CHANNEL(chan_caller, NULL, &bob_expected);
+ CREATE_ALICE_CHANNEL(chan_caller, &caller, &bob_expected);
ast_copy_string(charlie_expected.uniqueid, ast_channel_uniqueid(chan_caller), sizeof(charlie_expected.uniqueid));
ast_copy_string(charlie_expected.linkedid, ast_channel_linkedid(chan_caller), sizeof(charlie_expected.linkedid));
ast_copy_string(david_expected.uniqueid, ast_channel_uniqueid(chan_caller), sizeof(david_expected.uniqueid));
@@ -1010,6 +1140,7 @@
RAII_VAR(struct ast_cdr_config *, config, ao2_alloc(sizeof(*config), NULL),
ao2_cleanup);
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr alice_expected_one = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -1073,7 +1204,7 @@
SWAP_CONFIG(config, debug_cdr_config);
- CREATE_ALICE_CHANNEL(chan_caller, NULL, expected);
+ CREATE_ALICE_CHANNEL(chan_caller, &caller, expected);
COPY_IDS(chan_caller, &alice_expected_two);
ast_channel_priority_set(chan_caller, 1);
@@ -1110,6 +1241,7 @@
ao2_cleanup);
enum ast_test_result_state result = AST_TEST_NOT_RUN;
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -1140,7 +1272,7 @@
SWAP_CONFIG(config, debug_cdr_config);
- CREATE_ALICE_CHANNEL(chan_caller, NULL, &expected);
+ CREATE_ALICE_CHANNEL(chan_caller, &caller, &expected);
ast_channel_priority_set(chan_caller, 1);
EMULATE_APP_DATA(chan_caller, "Dial", CHANNEL_TECH_NAME "/Bob");
@@ -1199,6 +1331,7 @@
struct timespec to_sleep = {2, 0};
struct ast_flags fork_options = { 0, };
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr original = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -1260,7 +1393,7 @@
SWAP_CONFIG(config, unanswered_cdr_config);
- CREATE_ALICE_CHANNEL(chan, NULL, &original);
+ CREATE_ALICE_CHANNEL(chan, &caller, &original);
ast_copy_string(fork_expected_one.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_one.uniqueid));
ast_copy_string(fork_expected_one.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_one.linkedid));
ast_copy_string(fork_expected_two.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_two.uniqueid));
@@ -1401,6 +1534,7 @@
struct ast_flags fork_options = { 0, };
struct timespec to_sleep = {1, 0};
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr expected = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -1428,7 +1562,7 @@
SWAP_CONFIG(config, unanswered_cdr_config);
- CREATE_ALICE_CHANNEL(chan, NULL, &expected);
+ CREATE_ALICE_CHANNEL(chan, &caller, &expected);
while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR));
if (!ast_cdr_exists(ast_channel_name(chan))) {
@@ -1481,6 +1615,7 @@
struct ast_flags fork_options = { 0, };
struct timespec to_sleep = {1, 10000};
+ struct ast_party_caller caller = ALICE_CALLERID;
struct ast_cdr original = {
.clid = "\"Alice\" <100>",
.src = "100",
@@ -1530,7 +1665,7 @@
SWAP_CONFIG(config, debug_cdr_config);
- CREATE_ALICE_CHANNEL(chan, NULL, &original);
+ CREATE_ALICE_CHANNEL(chan, &caller, &original);
ast_copy_string(fork_expected_one.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_one.uniqueid));
ast_copy_string(fork_expected_one.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_one.linkedid));
ast_copy_string(fork_expected_two.uniqueid, ast_channel_uniqueid(chan), sizeof(fork_expected_two.uniqueid));
@@ -1625,6 +1760,8 @@
AST_TEST_UNREGISTER(test_cdr_unanswered_inbound_call);
AST_TEST_UNREGISTER(test_cdr_unanswered_outbound_call);
AST_TEST_UNREGISTER(test_cdr_single_party);
+ AST_TEST_UNREGISTER(test_cdr_single_bridge);
+ AST_TEST_UNREGISTER(test_cdr_single_twoparty_bridge);
AST_TEST_UNREGISTER(test_cdr_dial_unanswered);
AST_TEST_UNREGISTER(test_cdr_dial_congestion);
@@ -1654,7 +1791,11 @@
AST_TEST_REGISTER(test_cdr_channel_creation);
AST_TEST_REGISTER(test_cdr_unanswered_inbound_call);
AST_TEST_REGISTER(test_cdr_unanswered_outbound_call);
+
AST_TEST_REGISTER(test_cdr_single_party);
+ AST_TEST_REGISTER(test_cdr_single_bridge);
+ AST_TEST_REGISTER(test_cdr_single_twoparty_bridge);
+ /*AST_TEST_REGISTER(test_cdr_single_multiparty_bridge);*/
AST_TEST_REGISTER(test_cdr_dial_unanswered);
AST_TEST_REGISTER(test_cdr_dial_congestion);
@@ -1670,9 +1811,6 @@
AST_TEST_REGISTER(test_cdr_no_reset_cdr);
AST_TEST_REGISTER(test_cdr_fork_cdr);
- /*AST_TEST_REGISTER(test_cdr_single_bridge);
- AST_TEST_REGISTER(test_cdr_single_multiparty);*/
-
ast_test_register_init(TEST_CATEGORY, test_cdr_init_cb);
ast_test_register_cleanup(TEST_CATEGORY, test_cdr_cleanup_cb);
More information about the asterisk-commits
mailing list