[asterisk-commits] mjordan: branch mjordan/cdrs-of-doom r386874 - in /team/mjordan/cdrs-of-doom:...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Apr 29 18:12:52 CDT 2013
Author: mjordan
Date: Mon Apr 29 18:12:48 2013
New Revision: 386874
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386874
Log:
A whole lot of doxygen
Modified:
team/mjordan/cdrs-of-doom/apps/app_dial.c
team/mjordan/cdrs-of-doom/apps/app_queue.c
team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c
team/mjordan/cdrs-of-doom/channels/chan_dahdi.c
team/mjordan/cdrs-of-doom/channels/chan_iax2.c
team/mjordan/cdrs-of-doom/channels/chan_mgcp.c
team/mjordan/cdrs-of-doom/channels/chan_skinny.c
team/mjordan/cdrs-of-doom/funcs/func_cdr.c
team/mjordan/cdrs-of-doom/include/asterisk/cdr.h
team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h
team/mjordan/cdrs-of-doom/main/asterisk.c
team/mjordan/cdrs-of-doom/main/bridging.c
team/mjordan/cdrs-of-doom/main/cdr.c
team/mjordan/cdrs-of-doom/main/manager.c
team/mjordan/cdrs-of-doom/main/stasis_channels.c
team/mjordan/cdrs-of-doom/tests/test_cdr.c
Modified: team/mjordan/cdrs-of-doom/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/apps/app_dial.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/apps/app_dial.c (original)
+++ team/mjordan/cdrs-of-doom/apps/app_dial.c Mon Apr 29 18:12:48 2013
@@ -56,7 +56,6 @@
#include "asterisk/app.h"
#include "asterisk/causes.h"
#include "asterisk/rtp_engine.h"
-#include "asterisk/cdr.h"
#include "asterisk/manager.h"
#include "asterisk/privacy.h"
#include "asterisk/stringfields.h"
Modified: team/mjordan/cdrs-of-doom/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/apps/app_queue.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/apps/app_queue.c (original)
+++ team/mjordan/cdrs-of-doom/apps/app_queue.c Mon Apr 29 18:12:48 2013
@@ -5436,21 +5436,6 @@
if (res == -1) {
ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
}
- if (ast_cdr_isset_unanswered()) {
- /* channel contains the name of one of the outgoing channels
- in its CDR; zero out this CDR to avoid a dual-posting */
- struct callattempt *o;
- for (o = outgoing; o; o = o->q_next) {
- if (!o->chan) {
- continue;
- }
- /* BUGBUG: this is terrible */
- /*if (strcmp(ast_channel_cdr(o->chan)->dstchannel, ast_channel_cdr(qe->chan)->dstchannel) == 0) {
- ast_set_flag(ast_channel_cdr(o->chan), AST_CDR_FLAG_DISABLE);
- break;
- }*/
- }
- }
} else { /* peer is valid */
/* Ah ha! Someone answered within the desired timeframe. Of course after this
we will always return with -1 so that it is hung up properly after the
Modified: team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c (original)
+++ team/mjordan/cdrs-of-doom/bridges/bridge_softmix.c Mon Apr 29 18:12:48 2013
@@ -873,6 +873,10 @@
AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
struct softmix_channel *sc = bridge_channel->tech_pvt;
+ if (!sc) {
+ continue;
+ }
+
/* Update the sample rate to match the bridge's native sample rate if necessary. */
if (update_all_rates) {
set_softmix_bridge_data(softmix_data->internal_rate, softmix_data->internal_mixing_interval, bridge_channel, 1);
Modified: team/mjordan/cdrs-of-doom/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/channels/chan_dahdi.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/channels/chan_dahdi.c (original)
+++ team/mjordan/cdrs-of-doom/channels/chan_dahdi.c Mon Apr 29 18:12:48 2013
@@ -107,7 +107,6 @@
#include "asterisk/callerid.h"
#include "asterisk/adsi.h"
#include "asterisk/cli.h"
-#include "asterisk/cdr.h"
#include "asterisk/cel.h"
#include "asterisk/features.h"
#include "asterisk/musiconhold.h"
Modified: team/mjordan/cdrs-of-doom/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/channels/chan_iax2.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/channels/chan_iax2.c (original)
+++ team/mjordan/cdrs-of-doom/channels/chan_iax2.c Mon Apr 29 18:12:48 2013
@@ -77,7 +77,6 @@
#include "asterisk/cli.h"
#include "asterisk/translate.h"
#include "asterisk/md5.h"
-#include "asterisk/cdr.h"
#include "asterisk/crypto.h"
#include "asterisk/acl.h"
#include "asterisk/manager.h"
Modified: team/mjordan/cdrs-of-doom/channels/chan_mgcp.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/channels/chan_mgcp.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/channels/chan_mgcp.c (original)
+++ team/mjordan/cdrs-of-doom/channels/chan_mgcp.c Mon Apr 29 18:12:48 2013
@@ -67,7 +67,6 @@
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
-#include "asterisk/cdr.h"
#include "asterisk/astdb.h"
#include "asterisk/features.h"
#include "asterisk/app.h"
Modified: team/mjordan/cdrs-of-doom/channels/chan_skinny.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/channels/chan_skinny.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/channels/chan_skinny.c (original)
+++ team/mjordan/cdrs-of-doom/channels/chan_skinny.c Mon Apr 29 18:12:48 2013
@@ -67,7 +67,6 @@
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/say.h"
-#include "asterisk/cdr.h"
#include "asterisk/astdb.h"
#include "asterisk/features.h"
#include "asterisk/app.h"
Modified: team/mjordan/cdrs-of-doom/funcs/func_cdr.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/funcs/func_cdr.c?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/funcs/func_cdr.c (original)
+++ team/mjordan/cdrs-of-doom/funcs/func_cdr.c Mon Apr 29 18:12:48 2013
@@ -142,11 +142,6 @@
<optionlist>
<option name="f">
<para>Returns billsec or duration fields as floating point values.</para>
- </option>
- <option name="r">
- <para>Searches the entire stack of CDRs on the channel.
- If this option is not specified, only the most recent CDR
- is affected by the operation.</para>
</option>
<option name="u">
<para>Retrieves the raw, unprocessed value.</para>
@@ -163,10 +158,6 @@
<literal>userfield</literal>, and <literal>amaflags</literal>. You may, however, supply
a name not on the above list, and create your own variable, whose value can be changed
with this function, and this variable will be stored on the CDR.</para>
- <note><para>For setting CDR values, the <literal>r</literal> flag does not apply to
- setting the <literal>accountcode</literal>, <literal>userfield</literal>, or
- <literal>amaflags</literal>. These values will always be set on all CDRs that
- have not yet been finalized.</para>
<para>CDRs can only be modified before the bridge between two channels is
torn down. For example, CDRs may not be modified after the <literal>Dial</literal>
application has returned.</para></note>
@@ -189,41 +180,54 @@
static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse,
char *buf, size_t len)
{
+ char format_buf[128];
char *ret = NULL;
struct ast_flags flags = { 0 };
- char temp_buf[128];
+ RAII_VAR(char *, tempbuf, ast_malloc(128), ast_free);
+ char *info;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(variable);
AST_APP_ARG(options);
);
- if (ast_strlen_zero(parse) || !chan)
+ if (!chan || !tempbuf) {
return -1;
-
- AST_STANDARD_APP_ARGS(args, parse);
-
- if (!ast_strlen_zero(args.options))
+ }
+
+ if (ast_strlen_zero(parse)) {
+ ast_log(AST_LOG_WARNING, "FUNC_CDR requires a variable (FUNC_CDR(variable[,option]))\n)");
+ return -1;
+ }
+ info = ast_strdupa(parse);
+ AST_STANDARD_APP_ARGS(args, info);
+
+ if (!ast_strlen_zero(args.options)) {
ast_app_parse_options(cdr_func_options, &flags, NULL, args.options);
-
- /*ast_cdr_getvar(cdr, args.variable, tempbuf, sizeof(temp_buf),
- ast_test_flag(&flags, OPT_RECURSIVE));
-
- if (ast_test_flag(&flags, OPT_FLOAT) && (!strcasecmp("billsec", args.variable)
- || !strcasecmp("duration", args.variable))) {
- char format_buf[128];
+ }
+
+ if (ast_cdr_getvar(ast_channel_name(chan), args.variable, &tempbuf, sizeof(*tempbuf))) {
+ return 0;
+ }
+
+ if (ast_test_flag(&flags, OPT_FLOAT) && (!strcasecmp("billsec", args.variable) || !strcasecmp("duration", args.variable))) {
sprintf(format_buf, "%lf", temp_buf);
strcpy(temp_buf, format_buf);
} else if (!ast_test_flag(&flags, OPT_UNPARSED)) {
- if (!strcasecmp("start") || !strcasecmp("end")
- || (!strcasecmp("answer"))) {
+ if (!strcasecmp("start") || !strcasecmp("end") || (!strcasecmp("answer"))) {
} else if (!strcasecmp("disposition")) {
-
+ int disposition;
+ sscanf(tempbuf, "%8d", &disposition);
+ snprintf(format_buf, sizeof(format_buf), "%s", ast_cdr_disp2str(disposition));
+ strcpy(tempbuf, format_buf);
} else if (!strcasecmp("amaflags")) {
-
+ int amaflags;
+ sscanf(tempbuf, "%8d", &amaflags);
+ snprintf(format_buf, sizeof(format_buf), "%s", ast_channel_amaflags2string(amaflags));
+ strcpy(tempbuf, format_buf);
}
}
-*/
+
ast_copy_string(buf, temp_buf, len);
return ret ? 0 : -1;
}
Modified: team/mjordan/cdrs-of-doom/include/asterisk/cdr.h
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/include/asterisk/cdr.h?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/include/asterisk/cdr.h (original)
+++ team/mjordan/cdrs-of-doom/include/asterisk/cdr.h Mon Apr 29 18:12:48 2013
@@ -164,24 +164,6 @@
void ast_cdr_set_config(struct ast_cdr_config *config);
/*!
- * \brief Return whether or not the CDR engine accepts unanswered CDRs
- *
- * TODO: this should probably get removed
- *
- * \retval 0 the engine will not dispatch unanswered records
- * \retval 1 the engine will dispatch unanswered records
- */
-int ast_cdr_isset_unanswered(void);
-
-/*!
- * \brief Return whether or not a channel has a CDR where it is the Party A
- *
- * \retval 0 if the channel does not have a CDR
- * \retval 1 if the channel does have a CDR
- */
-int ast_cdr_exists(const char *channel_name);
-
-/*!
* \since 12
* \brief Format a CDR variable from an already posted CDR
*
@@ -277,9 +259,15 @@
*/
int ast_cdr_reset(const char *channel_name, struct ast_flags *options);
+/*!
+ * \brief Serializes all the data and variables for a current CDR record
+ * \param channel_name The channel to get the CDR for
+ * \param buf A buffer to use for formatting the data
+ * \param delim A delimeter to use to separate variable keys/values
+ * \param sep A separator to use between nestings
+ * \retval the total number of serialized variables
+ */
int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep);
-
-int ast_cdr_copy_vars(struct ast_cdr *to_cdr, struct ast_cdr *from_cdr);
/*!
* \brief CDR backend callback
@@ -290,7 +278,7 @@
typedef int (*ast_cdrbe)(struct ast_cdr *cdr);
/*! \brief Return TRUE if CDR subsystem is enabled */
-int check_cdr_enabled(void);
+int ast_cdr_is_enabled(void);
/*!
* \brief Allocate a CDR record
@@ -334,25 +322,6 @@
*/
void ast_cdr_unregister(const char *name);
-
-
-/*!
- * \brief Detaches the detail record for posting (and freeing) either now or at a
- * later time in bulk with other records during batch mode operation.
- * \param cdr Which CDR to detach from the channel thread
- * Prevents the channel thread from blocking on the CDR handling
- * Returns nothing
- */
-void ast_cdr_detach(struct ast_cdr *cdr);
-
-/*!
- * \brief Spawns (possibly) a new thread to submit a batch of CDRs to the backend engines
- * \param shutdown Whether or not we are shutting down
- * Blocks the asterisk shutdown procedures until the CDR data is submitted.
- * Returns nothing
- */
-void ast_cdr_submit_batch(int shutdown);
-
/*!
* \brief Disposition to a string
* \param disposition input binary form
@@ -361,8 +330,6 @@
*/
const char *ast_cdr_disp2str(int disposition);
-
-
/*!
* \brief Set CDR user field for channel (stored in CDR)
*
Modified: team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h?view=diff&rev=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h (original)
+++ team/mjordan/cdrs-of-doom/include/asterisk/stasis_channels.h Mon Apr 29 18:12:48 2013
@@ -52,6 +52,9 @@
AST_STRING_FIELD(exten); /*!< Dialplan: Current extension number */
AST_STRING_FIELD(caller_name); /*!< Caller ID Name */
AST_STRING_FIELD(caller_number); /*!< Caller ID Number */
+ AST_STRING_FIELD(dnid); /*!< Dialed ID Number */
+ AST_STRING_FIELD(caller_subaddr); /*!< Caller subaddress */
+ AST_STRING_FIELD(dialed_subaddr); /*!< Dialed subaddress */
AST_STRING_FIELD(connected_name); /*!< Connected Line Name */
AST_STRING_FIELD(connected_number); /*!< Connected Line Number */
);
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=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/main/asterisk.c (original)
+++ team/mjordan/cdrs-of-doom/main/asterisk.c Mon Apr 29 18:12:48 2013
@@ -598,7 +598,7 @@
ast_cli(a->fd, " -------------\n");
ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
- ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
+ ast_cli(a->fd, " Call data records: %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled");
ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
/*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
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=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/main/bridging.c (original)
+++ team/mjordan/cdrs-of-doom/main/bridging.c Mon Apr 29 18:12:48 2013
@@ -518,6 +518,10 @@
/* BUGBUG If this was an outbound channel and it is not hung up, clear the
* outbound flag
*/
+ if (ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_OUTGOING)
+ && !ast_test_flag(ast_channel_flags(bridge_channel->chan), AST_FLAG_ZOMBIE)) {
+
+ }
/* Remove channel from the bridge */
if (!bridge_channel->suspended) {
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=386874&r1=386873&r2=386874
==============================================================================
--- team/mjordan/cdrs-of-doom/main/cdr.c (original)
+++ team/mjordan/cdrs-of-doom/main/cdr.c Mon Apr 29 18:12:48 2013
@@ -198,6 +198,9 @@
ast_verb(1, (fmt), ##__VA_ARGS__); \
} } while (0)
+static void cdr_detach(struct ast_cdr *cdr);
+static void cdr_submit_batch(int shutdown);
+
/*! \brief The configuration settings for this module */
struct module_config {
struct ast_cdr_config *general; /*< CDR global settings */
@@ -293,6 +296,7 @@
static struct ast_sched_context *sched;
static int cdr_sched = -1;
+AST_MUTEX_DEFINE_STATIC(cdr_sched_lock);
static pthread_t cdr_thread = AST_PTHREADT_NULL;
AST_MUTEX_DEFINE_STATIC(cdr_batch_lock);
@@ -310,8 +314,10 @@
/*! \brief Message router for stasis messages regarding channel state */
static struct stasis_message_router *stasis_router;
+/*! \brief Our subscription for bridges */
static struct stasis_subscription *bridge_subscription;
+/*! \brief Our subscription for channels */
static struct stasis_subscription *channel_subscription;
/*! \brief The parent topic for all topics we want to aggregate for CDRs */
@@ -324,57 +330,107 @@
* implementation, it is safe to leave it NULL.
*/
struct cdr_object_fn_table {
- /*! Name of the subclass */
+ /*! \brief 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
+ /*!
+ * \brief 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
+ /*!
+ * \brief 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,
+ int (* const process_party_a)(struct cdr_object *cdr,
struct ast_channel_snapshot *snapshot);
- /*! Process a Party B update for the \ref cdr_object
+ /*!
+ * \brief 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,
+ void (* const process_party_b)(struct cdr_object *cdr,
struct ast_channel_snapshot *snapshot);
- /*! Process the beginning of a dial. A dial message implies one of two
+ /*!
+ * \brief 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.
+ *
+ * \param cdr The \ref cdr_object
+ * \param caller The originator of the dial attempt
+ * \param peer The destination of the dial attempt
+ *
+ * \retval 0 if the parties in the dial were handled by this CDR
+ * \retval 1 if the parties could not be handled by this CDR
*/
int (* const process_dial_begin)(struct cdr_object *cdr,
struct ast_channel_snapshot *caller,
struct ast_channel_snapshot *peer);
+
+ /*!
+ * \brief Process the end of a dial. At the end of a dial, a CDR can be
+ * transitioned into one of two states - DialedPending
+ * (\ref dialed_pending_state_fn_table) or Finalized
+ * (\ref finalized_state_fn_table).
+ *
+ * \param cdr The \ref cdr_object
+ * \param caller The originator of the dial attempt
+ * \param peer the Destination of the dial attempt
+ * \param dial_status What happened
+ *
+ * \retval 0 if the parties in the dial were handled by this CDR
+ * \retval 1 if the parties could not be handled by this CDR
+ */
int (* const process_dial_end)(struct cdr_object *cdr,
struct ast_channel_snapshot *caller,
struct ast_channel_snapshot *peer,
const char *dial_status);
+
+ /*!
+ * \brief Process the entering of a bridge by this CDR. The purpose of this
+ * callback is to have the CDR prepare itself for the bridge and attempt to
+ * find a valid Party B. The act of creating new CDRs based on the entering
+ * of this channel into the bridge is handled by the higher level message
+ * handler.
+ *
+ * \param cdr The\ref cdr_object
+ * \param bridge The bridge that the Party A just entered into
+ * \param channel The \ref ast_channel_snapshot for this CDR's Party A
+ *
+ * \retval 0 This CDR found a Party B for itself and updated it, or there
+ * was no Party B to find (we're all alone)
+ * \retval 1 This CDR couldn't find a Party B, and there were options
+ */
int (* const process_bridge_enter)(struct cdr_object *cdr,
struct ast_bridge_snapshot *bridge,
struct ast_channel_snapshot *channel);
+
+ /*!
+ * \brief Process the leaving of a bridge by this CDR.
+ *
+ * \param cdr The\ref cdr_object
+ * \param bridge The bridge that the Party A just left
+ * \param channel The \ref ast_channel_snapshot for this CDR's Party A
+ *
+ * \retval 0 This CDR left successfully
+ * \retval 1 Error
+ */
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 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);
@@ -385,11 +441,22 @@
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);
+/*!
+ * \brief The virtual table for the Single state.
+ *
+ * A \ref cdr_object starts off in this state. This represents a channel that
+ * has no Party B information itself.
+ *
+ * A \ref cdr_object from this state can go into any of the following states:
+ * * \ref dial_state_fn_table
+ * * \ref bridge_state_fn_table
+ * * \ref finalized_state_fn_table
+ */
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,
- .process_party_b_update = single_state_process_party_b,
+ .process_party_a = base_process_party_a,
+ .process_party_b = 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,
@@ -401,23 +468,77 @@
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);
+/*!
+ * \brief The virtual table for the Dial state.
+ *
+ * A \ref cdr_object that has begun a dial operation. This state is entered when
+ * the Party A for a CDR is determined to be dialing out to a Party B or when
+ * a CDR is for an originated channel (in which case the Party A information is
+ * the originated channel, and there is no Party B).
+ *
+ * A \ref cdr_object from this state can go in any of the following states:
+ * * \ref dialed_pending_state_fn_table
+ * * \ref bridge_state_fn_table
+ * * \ref finalized_state_fn_table
+ */
struct cdr_object_fn_table dial_state_fn_table = {
.name = "Dial",
- .process_party_a_update = base_process_party_a,
- .process_party_b_update = dial_state_process_party_b,
+ .process_party_a = base_process_party_a,
+ .process_party_b = dial_state_process_party_b,
.process_dial_begin = dial_state_process_dial_begin,
.process_dial_end = dial_state_process_dial_end,
.process_bridge_enter = dial_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);
+
+/*!
+ * \brief The virtual table for the Dialed Pending state.
+ *
+ * A \ref cdr_object that has successfully finished a dial operation, but we
+ * don't know what they're going to do yet. It's theoretically possible to dial
+ * a party and then have that party not be bridged with the caller; likewise,
+ * an origination can complete and the channel go off and execute dialplan. The
+ * pending state acts as a bridge between either:
+ * * Entering a bridge
+ * * Getting a new CDR for new dialplan execution
+ * * Switching from being originated to executing dialplan
+ *
+ * A \ref cdr_object from this state can go in any of the following states:
+ * * \ref single_state_fn_table
+ * * \ref dialed_pending_state_fn_table
+ * * \ref bridge_state_fn_table
+ * * \ref finalized_state_fn_table
+ */
+struct cdr_object_fn_table dialed_pending_state_fn_table = {
+ .name = "DialedPending",
+ .process_party_a = 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 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);
+/*!
+ * \brief The virtual table for the Bridged state
+ *
+ * A \ref cdr_object enters this state when it receives notification that the
+ * channel has entered a bridge.
+ *
+ * A \ref cdr_object from this state can go to:
+ * * \ref finalized_state_fn_table
+ * * \ref pending_state_fn_table
+ */
struct cdr_object_fn_table bridge_state_fn_table = {
.name = "Bridged",
- .process_party_a_update = base_process_party_a,
- .process_party_b_update = bridge_state_process_party_b,
+ .process_party_a = base_process_party_a,
+ .process_party_b = bridge_state_process_party_b,
.process_bridge_leave = bridge_state_process_bridge_leave,
};
@@ -426,36 +547,41 @@
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);
+/*!
+ * \brief The virtual table for the Pending state
+ *
+ * At certain times, we don't know where to go with the CDR. A good example is
+ * when a channel leaves a bridge - we don't know if the channel is about to
+ * be hung up; if it is about to go execute dialplan; dial someone; go into
+ * another bridge, etc. At these times, the CDR goes into pending and observes
+ * the messages that come in next to infer where the next logical place to go
+ * is.
+ *
+ * In this state, a CDR can go anywhere!
+ */
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_party_a = 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 int finalized_state_process_party_a(struct cdr_object *cdr, struct ast_channel_snapshot *snapshot);
+/*!
+ * \brief The virtual table for the finalized state.
+ *
+ * Once in the finalized state, the CDR is done. No modifications can be made
+ * to the CDR.
+ */
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,
+ .process_party_a = finalized_state_process_party_a,
};
/*! \brief A wrapper object around a snapshot.
@@ -464,22 +590,22 @@
struct cdr_object_snapshot {
struct ast_channel_snapshot *snapshot; /*!< The channel snapshot */
char userfield[AST_MAX_USER_FIELD]; /*!< Userfield for the channel */
- unsigned int flags;
+ unsigned int flags; /*!< Specific flags for this party */
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;
- struct cdr_object_fn_table *fn_table;
-
- enum ast_cdr_disposition disposition;
- struct timeval start;
- struct timeval answer;
- struct timeval end;
- unsigned int sequence;
- struct ast_flags flags;
+ struct cdr_object_snapshot party_a; /*!< The Party A information */
+ struct cdr_object_snapshot party_b; /*!< The Party B information */
+ struct cdr_object_fn_table *fn_table; /*!< The current virtual table */
+
+ enum ast_cdr_disposition disposition; /*!< The disposition of the CDR */
+ struct timeval start; /*!< When this CDR was created */
+ struct timeval answer; /*!< Either when the channel was answered, or when the path between channels was established */
+ struct timeval end; /*!< When this CDR was finalized */
+ unsigned int sequence; /*!< A monotonically increasing number for each CDR */
+ struct ast_flags flags; /*!< Flags on the CDR */
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(linkedid); /*< Linked ID. Cached here as it may change out from party A, which must be immutable */
AST_STRING_FIELD(name); /*< Channel name of party A. Cached here as the party A address may change */
@@ -489,8 +615,13 @@
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)
+/*!
+ * \brief Copy variables from one list to another
+ * \param to_list destination
+ * \param from_list source
+ * \retval The number of copied variables
+ */
+static int copy_variables(struct varshead *to_list, struct varshead *from_list)
{
struct ast_var_t *variables, *newvariable = NULL;
const char *var, *val;
@@ -509,6 +640,24 @@
return x;
}
+/*!
+ * \brief Delete all variables from a variable list
+ * \param headp The head pointer to the variable list to delete
+ */
+static void free_variables(struct varshead *headp)
+{
+ struct ast_var_t *vardata;
+
+ while ((vardata = AST_LIST_REMOVE_HEAD(headp, entries))) {
+ ast_var_delete(vardata);
+ }
+}
+
+/*!
+ * \brief Copy a snapshot and its details
+ * \param dst The destination
+ * \param src The source
+ */
static void cdr_object_snapshot_copy(struct cdr_object_snapshot *dst, struct cdr_object_snapshot *src)
{
if (dst->snapshot) {
@@ -518,13 +667,26 @@
ao2_ref(dst->snapshot, +1);
strcpy(dst->userfield, src->userfield);
dst->flags = src->flags;
- copy_vars(&dst->variables, &src->variables);
-}
-
-/* NON-VIRTUAL FUNCTIONS */
-
-static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table);
-
+ copy_variables(&dst->variables, &src->variables);
+}
+
+/*!
+ * \brief Transition a \ref cdr_object to a new state
+ * \param cdr The \ref cdr_object to transition
+ * \param fn_table The \ref cdr_object_fn_table state to go to
+ */
+static void cdr_object_transition_state(struct cdr_object *cdr, struct cdr_object_fn_table *fn_table)
+{
+ RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
+
+ CDR_DEBUG(mod_cfg, "%p - Transitioning CDR for %s from state %s to %s\n",
+ cdr, cdr->party_a.snapshot->name,
+ cdr->fn_table ? cdr->fn_table->name : "NONE", fn_table->name);
+ cdr->fn_table = fn_table;
+ if (cdr->fn_table->init_function) {
+ cdr->fn_table->init_function(cdr);
+ }
+}
/*! \internal
* \brief Hash function for containers of CDRs indexing by Party A name */
static int cdr_object_channel_hash_fn(const void *obj, const int flags)
@@ -574,6 +736,9 @@
return 0;
}
+/*!
+ * \brief \ref cdr_object Destructor
+ */
static void cdr_object_dtor(void *obj)
{
struct cdr_object *cdr = obj;
@@ -598,6 +763,13 @@
}
}
+/*!
+ * \brief \ref cdr_object constructor
+ * \param chan The \ref ast_channel_snapshot that is the CDR's Party A
+ *
+ * This implicitly sets the state of the newly created CDR to the Single state
+ * (\ref single_state_fn_table)
+ */
static struct cdr_object *cdr_object_alloc(struct ast_channel_snapshot *chan)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
@@ -621,13 +793,17 @@
cdr->party_a.snapshot = chan;
ao2_ref(cdr->party_a.snapshot, +1);
- CDR_DEBUG(mod_cfg, "%p - created CDR for channel %s\n", cdr, chan->name);
+ CDR_DEBUG(mod_cfg, "%p - Created CDR for channel %s\n", cdr, chan->name);
cdr_object_transition_state(cdr, &single_state_fn_table);
return cdr;
}
+/*!
+ * \brief Create a new \ref cdr_object and append it to an existing chain
+ * \param cdr The \ref cdr_object to append to
+ */
static struct cdr_object *cdr_object_create_and_append(struct cdr_object *cdr)
{
struct cdr_object *new_cdr;
@@ -654,22 +830,61 @@
return new_cdr;
}
-static struct ast_channel_snapshot *cdr_object_determine_party_a(struct ast_channel_snapshot *left, struct ast_channel_snapshot *right)
-{
- /* TODO: check party a flag */
-
- if (left->creationtime.tv_sec < right->creationtime.tv_sec) {
+/*!
+ * \brief Return whether or not a \ref ast_channel_snapshot is for a channel
+ * that was created as the result of a dial operation
+ *
+ * \retval 0 the channel was not created as the result of a dial
+ * \retval 1 the channel was created as the result of a dial
+ */
+static int snapshot_is_dialed(struct ast_channel_snapshot *snapshot)
+{
+ return (ast_test_flag(&snapshot->flags, AST_FLAG_OUTGOING)
+ && !(ast_test_flag(&snapshot->flags, AST_FLAG_ORIGINATED)));
+}
+
+/*!
+ * \brief Given two CDR snapshots, figure out who should be Party A for the
+ * resulting CDR
+ * \param left One of the snapshots
+ * \param right The other snapshot
+ * \retval The snapshot that won
+ */
+static struct cdr_object_snapshot *cdr_object_pick_party_a(struct cdr_object_snapshot *left, struct cdr_object_snapshot *right)
+{
+ /* Check whether or not the party is dialed. A dialed party is never the
+ * Party A with a party that was not dialed.
+ */
+ if (!snapshot_is_dialed(left->snapshot) && snapshot_is_dialed(right->snapshot)) {
return left;
- } else if (left->creationtime.tv_sec > right->creationtime.tv_sec) {
+ } else if (snapshot_is_dialed(left->snapshot) && !snapshot_is_dialed(right->snapshot)) {
return right;
+ }
+
+ /* Try the Party A flag */
+ if (ast_test_flag(left, AST_CDR_FLAG_PARTY_A) && !ast_test_flag(right, AST_CDR_FLAG_PARTY_A)) {
+ return left;
+ } else if (!ast_test_flag(right, AST_CDR_FLAG_PARTY_A) && ast_test_flag(right, AST_CDR_FLAG_PARTY_A)) {
+ return right;
+ }
+
+ /* Neither party is dialed and neither has the Party A flag - defer to
+ * creation time */
+ if (left->snapshot->creationtime.tv_sec < right->snapshot->creationtime.tv_sec) {
+ return left;
+ } else if (left->snapshot->creationtime.tv_sec > right->snapshot->creationtime.tv_sec) {
+ return right;
+ } else if (left->snapshot->creationtime.tv_usec > right->snapshot->creationtime.tv_usec) {
+ return right;
} else {
- if (left->creationtime.tv_usec > right->creationtime.tv_usec) {
- return right;
- }
+ /* Okay, fine, take the left one */
return left;
}
}
+/*!
+ * Compute the duration for a \ref cdr_object
+ */
static long cdr_object_get_duration(struct cdr_object *cdr)
{
if (ast_tvzero(cdr->end)) {
@@ -679,6 +894,9 @@
}
}
+/*!
+ * \brief Compute the billsec for a \ref cdr_object
+ */
static long cdr_object_get_billsec(struct cdr_object *cdr)
{
RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
@@ -698,6 +916,13 @@
return ms;
}
+/*!
+ * \brief Create a chain of \ref ast_cdr objects from a chain of \ref cdr_object
+ * suitable for consumption by the registered CDR backends
+ * \param cdr The \ref cdr_object to convert to a public record
+ * \retval A chain of \ref ast_cdr objects on success
+ * \retval NULL on failure
+ */
static struct ast_cdr *cdr_object_create_public_records(struct cdr_object *cdr)
{
struct ast_cdr *pub_cdr = NULL, *cdr_prev;
@@ -708,11 +933,8 @@
while (cdr) {
struct ast_cdr *cdr_copy;
- /* Don't create records for CDRs where the party A is an outgoing,
- * non-originated channel.
- */
- if (ast_test_flag(&cdr->party_a.snapshot->flags, AST_FLAG_OUTGOING)
- && !ast_test_flag(&cdr->party_a.snapshot->flags, AST_FLAG_ORIGINATED)) {
+ /* Don't create records for CDRs where the party A was a dialed channel */
+ if (snapshot_is_dialed(cdr->party_a.snapshot)) {
cdr = cdr->next;
continue;
}
@@ -731,7 +953,6 @@
ast_copy_string(cdr_copy->accountcode, party_a->accountcode, sizeof(cdr_copy->accountcode));
cdr_copy->amaflags = party_a->amaflags;
ast_copy_string(cdr_copy->channel, party_a->name, sizeof(cdr_copy->channel));
- /* XXX TODO: we need to get the full caller ID somehow */
ast_callerid_merge(cdr_copy->clid, sizeof(cdr_copy->clid), party_a->caller_name, party_a->caller_number, "");
ast_copy_string(cdr_copy->src, party_a->caller_number, sizeof(cdr_copy->src));
ast_copy_string(cdr_copy->uniqueid, party_a->uniqueid, sizeof(cdr_copy->uniqueid));
@@ -739,30 +960,34 @@
ast_copy_string(cdr_copy->lastdata, party_a->data, sizeof(cdr_copy->lastdata));
ast_copy_string(cdr_copy->dst, party_a->exten, sizeof(cdr_copy->dst));
ast_copy_string(cdr_copy->dcontext, party_a->context, sizeof(cdr_copy->dcontext));
- ast_copy_string(cdr_copy->userfield, cdr->party_a.userfield, sizeof(cdr_copy->userfield));
- /* XXX TODO: this should just happen automatically */
- ast_copy_flags(cdr_copy, &cdr->flags, AST_FLAGS_ALL);
/* Party B */
if (party_b) {
ast_copy_string(cdr_copy->dstchannel, party_b->name, sizeof(cdr_copy->dstchannel));
ast_copy_string(cdr_copy->peeraccount, party_b->accountcode, sizeof(cdr_copy->peeraccount));
- }
-
- /* Timestamps */
+ if (!ast_strlen_zero(cdr->party_b.userfield)) {
[... 1657 lines stripped ...]
More information about the asterisk-commits
mailing list