[asterisk-commits] seanbright: branch group/NoLossCDR-Redux2 r105377 - in /team/group/NoLossCDR-...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Feb 29 10:33:19 CST 2008
Author: seanbright
Date: Fri Feb 29 10:33:18 2008
New Revision: 105377
URL: http://svn.digium.com/view/asterisk?view=rev&rev=105377
Log:
Change the name of some data types (ast_cdr_beitem -> ast_cdr_backend), convert
the static character buffers to stringfields, extracted a common cleanup
function for ast_cdr_backends, fixed some unlock problems if backend
registration failed and a few other misc. changes/cleanup.
Modified:
team/group/NoLossCDR-Redux2/include/asterisk/cdr.h
team/group/NoLossCDR-Redux2/main/cdr.c
Modified: team/group/NoLossCDR-Redux2/include/asterisk/cdr.h
URL: http://svn.digium.com/view/asterisk/team/group/NoLossCDR-Redux2/include/asterisk/cdr.h?view=diff&rev=105377&r1=105376&r2=105377
==============================================================================
--- team/group/NoLossCDR-Redux2/include/asterisk/cdr.h (original)
+++ team/group/NoLossCDR-Redux2/include/asterisk/cdr.h Fri Feb 29 10:33:18 2008
@@ -173,14 +173,15 @@
/*!
* \brief Register a CDR handling engine
* \param name name associated with the particular CDR handler
- * \param desc description of the CDR handler
+ * \param sink_name the name of the sink we are registering
+ * \param description description of the CDR handler
* \param be function pointer to a CDR handler
* \param cleanup function pointer to a CDR sink cleanup handler
* Used to register a Call Detail Record handler.
* \retval 0 on success.
* \retval -1 on error
*/
-int ast_cdr_register(const char *name, const char *name_detail, const char *desc, ast_cdrbe be, ast_cdrbe_cleanup cleanup, void *be_data);
+int ast_cdr_register(const char *name, const char *sink_name, const char *description, ast_cdrbe be, ast_cdrbe_cleanup cleanup, void *be_data);
/*!
* \brief Unregister a CDR handling engine
Modified: team/group/NoLossCDR-Redux2/main/cdr.c
URL: http://svn.digium.com/view/asterisk/team/group/NoLossCDR-Redux2/main/cdr.c?view=diff&rev=105377&r1=105376&r2=105377
==============================================================================
--- team/group/NoLossCDR-Redux2/main/cdr.c (original)
+++ team/group/NoLossCDR-Redux2/main/cdr.c Fri Feb 29 10:33:18 2008
@@ -24,12 +24,12 @@
*
* \note Includes code and algorithms from the Zapata library.
*
- * \note We do a lot of checking here in the CDR code to try to be sure we don't ever let a CDR slip
- * through our fingers somehow. If someone allocates a CDR, it must be completely handled normally
- * or a WARNING shall be logged, so that we can best keep track of any escape condition where the CDR
- * isn't properly generated and posted.
+ * \note We do a lot of checking here in the CDR code to try to be sure we don't
+ * ever let a CDR slip through our fingers somehow. If someone allocates a CDR,
+ * it must be completely handled normally or a WARNING shall be logged, so that
+ * we can best keep track of any escape condition where the CDR isn't properly
+ * generated and posted.
*/
-
#include "asterisk.h"
@@ -51,19 +51,19 @@
#include "asterisk/stringfields.h"
#include "asterisk/module.h"
-static void *do_cdr(void *data);
-
/*! Default AMA flag for billing records (CDR's) */
int ast_default_amaflags = AST_CDR_DOCUMENTATION;
char ast_default_accountcode[AST_MAX_ACCOUNT_CODE];
-struct ast_cdr_beitem {
- char name[20];
- char name_detail[20];
- char desc[80];
+struct ast_cdr_backend {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name);
+ AST_STRING_FIELD(sink_name);
+ AST_STRING_FIELD(description);
+ );
ast_cdrbe be;
ast_cdrbe_cleanup cleanup;
- void *be_data;
+ void *config;
int cancel_thread;
int waiting_cdrs;
pthread_t cdr_thread;
@@ -71,10 +71,13 @@
ast_cond_t cdr_retry_cond;
ast_mutex_t retry_poll_lock;
AST_LIST_HEAD(, ast_cdr) cdr_queue;
- AST_RWLIST_ENTRY(ast_cdr_beitem) list;
+ AST_RWLIST_ENTRY(ast_cdr_backend) list;
};
-static AST_RWLIST_HEAD_STATIC(be_list, ast_cdr_beitem);
+static AST_RWLIST_HEAD_STATIC(backends, ast_cdr_backend);
+
+static void *do_cdr(void *data);
+static void ast_cdr_backend_free(struct ast_cdr_backend *backend);
#define SAFE_SHUTDOWN_DEFAULT 1
#define MAX_QUEUE_SIZE_DEFAULT 1000
@@ -99,80 +102,91 @@
/*! Register a CDR driver. Each registered CDR driver generates a CDR
\return 0 on success, -1 on failure
*/
-int ast_cdr_register(const char *name, const char *name_detail, const char *desc, ast_cdrbe be, ast_cdrbe_cleanup cleanup, void *be_data)
-{
- struct ast_cdr_beitem *i = NULL;
-
- if (!name || !desc)
+int ast_cdr_register(const char *name, const char *sink_name, const char *description, ast_cdrbe be, ast_cdrbe_cleanup cleanup, void *config)
+{
+ struct ast_cdr_backend *backend = NULL;
+
+ if (!name || !description) {
+ ast_log(LOG_ERROR, "CDR Backend registration requires both the 'name' and 'desc' arguments to be non-NULL.\n");
return -1;
+ }
if (!be) {
- ast_log(LOG_WARNING, "CDR engine '%s' lacks backend\n", name);
+ ast_log(LOG_ERROR, "CDR Backend registration for '%s' requires the 'be' argument to be non-NULL.\n", name);
return -1;
}
- AST_RWLIST_WRLOCK(&be_list);
- AST_RWLIST_TRAVERSE(&be_list, i, list) {
- if (!strcasecmp(name, i->name) && !strcasecmp(name_detail, i->name_detail)) {
- ast_log(LOG_WARNING, "Already have a CDR backend called '%s - %s'\n", name, name_detail);
- AST_RWLIST_UNLOCK(&be_list);
+ AST_RWLIST_WRLOCK(&backends);
+ AST_RWLIST_TRAVERSE(&backends, backend, list) {
+ if (!strcasecmp(name, backend->name) && !strcasecmp(sink_name, backend->sink_name)) {
+ ast_log(LOG_WARNING, "Already have a CDR backend called '%s - %s'\n", name, sink_name);
+ AST_RWLIST_UNLOCK(&backends);
return -1;
}
}
- if (!(i = ast_calloc(1, sizeof(struct ast_cdr_beitem))))
+ backend = ast_calloc(1, sizeof(*backend));
+
+ if (!backend || ast_string_field_init(backend, 120)) {
+ if (backend) {
+ ast_free(backend);
+ backend = NULL;
+ }
+ AST_RWLIST_UNLOCK(&backends);
return -1;
-
- i->be = be;
- i->cleanup = cleanup;
- i->cancel_thread = 0;
- i->waiting_cdrs = 0;
- ast_copy_string(i->name, name, sizeof(i->name));
- if (name_detail)
- ast_copy_string(i->name_detail, name_detail, sizeof(i->name_detail));
- else
- ast_copy_string(i->name_detail, "", sizeof(i->name_detail));
-
- ast_copy_string(i->desc, desc, sizeof(i->desc));
- i->be_data = be_data;
- ast_cond_init(&i->cdr_pending_cond, NULL);
- ast_cond_init(&i->cdr_retry_cond, NULL);
- if (ast_pthread_create_background(&i->cdr_thread, NULL, do_cdr, i) < 0)
+ }
+
+ ast_string_field_set(backend, name, name);
+ ast_string_field_set(backend, sink_name, sink_name);
+ ast_string_field_set(backend, description, description);
+
+ backend->be = be;
+ backend->cleanup = cleanup;
+ backend->cancel_thread = 0;
+ backend->waiting_cdrs = 0;
+ backend->config = config;
+
+ ast_cond_init(&backend->cdr_pending_cond, NULL);
+ ast_cond_init(&backend->cdr_retry_cond, NULL);
+ if (ast_pthread_create_background(&backend->cdr_thread, NULL, do_cdr, backend) < 0) {
ast_log(LOG_ERROR, "Unable to start CDR thread.\n");
- AST_RWLIST_INSERT_HEAD(&be_list, i, list);
- AST_RWLIST_UNLOCK(&be_list);
+ ast_cond_destroy(&backend->cdr_pending_cond);
+ ast_cond_destroy(&backend->cdr_retry_cond);
+ ast_string_field_free_memory(backend);
+ ast_free(backend);
+ AST_RWLIST_UNLOCK(&backends);
+ return -1;
+ }
+
+ AST_RWLIST_INSERT_HEAD(&backends, backend, list);
+ AST_RWLIST_UNLOCK(&backends);
return 0;
}
/*! unregister a CDR driver */
-void ast_cdr_unregister(const char *name, const char *name_detail)
-{
- struct ast_cdr_beitem *item = NULL;
-
- AST_RWLIST_WRLOCK(&be_list);
- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, item, list) {
- if (!strcasecmp(name, item->name) && (!name_detail || !strcasecmp(name_detail, item->name_detail))) {
- item->cancel_thread = 1;
- /* signal the thread so it can exit */
- ast_cond_signal(&item->cdr_pending_cond);
- /* wait for thread to exit so we can clean up */
- pthread_join(item->cdr_thread, NULL);
- item->cdr_thread = AST_PTHREADT_NULL;
- ast_cond_destroy(&item->cdr_pending_cond);
- ast_cond_destroy(&item->cdr_retry_cond);
+void ast_cdr_unregister(const char *name, const char *sink_name)
+{
+ struct ast_cdr_backend *backend = NULL;
+
+ AST_RWLIST_WRLOCK(&backends);
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&backends, backend, list) {
+ if (!strcasecmp(name, backend->name) && (!sink_name || !strcasecmp(sink_name, backend->sink_name))) {
AST_RWLIST_REMOVE_CURRENT(list);
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Unregistered '%s - %s' CDR backend\n", item->name, item->name_detail);
- if (item->cleanup)
- item->cleanup(item->be_data);
- ast_free(item);
- if (name_detail)
+
+ /* Free the backend/sink */
+ ast_cdr_backend_free(backend);
+
+ if (sink_name) {
+ ast_verb(2, "Unregistered '%s' CDR backend (Sink: '%s')\n", name, sink_name);
break;
+ } else {
+ ast_verb(2, "Unregistered '%s' CDR backend\n", name);
+ }
}
}
AST_RWLIST_TRAVERSE_SAFE_END;
- AST_RWLIST_UNLOCK(&be_list);
+ AST_RWLIST_UNLOCK(&backends);
}
/*! Duplicate a CDR record
@@ -996,7 +1010,7 @@
static void post_cdr(struct ast_cdr *cdr)
{
char *chan;
- struct ast_cdr_beitem *i;
+ struct ast_cdr_backend *i;
for ( ; cdr ; cdr = cdr->next) {
chan = S_OR(cdr->channel, "<unknown>");
@@ -1010,8 +1024,8 @@
continue;
/* add a ref to make sure we dont have a race condition */
ast_atomic_fetchadd_int(&cdr->usecount, +1);
- AST_RWLIST_RDLOCK(&be_list);
- AST_RWLIST_TRAVERSE(&be_list, i, list) {
+ AST_RWLIST_RDLOCK(&backends);
+ AST_RWLIST_TRAVERSE(&backends, i, list) {
AST_LIST_LOCK(&i->cdr_queue);
ast_debug(1, "cdr inserted into queue/list for: %s\n", i->name);
/* increment usecount of this cdr record */
@@ -1025,7 +1039,7 @@
ast_cond_signal(&i->cdr_pending_cond);
AST_LIST_UNLOCK(&i->cdr_queue);
}
- AST_RWLIST_UNLOCK(&be_list);
+ AST_RWLIST_UNLOCK(&backends);
if (ast_atomic_fetchadd_int(&cdr->usecount, -1) == 1) {
ast_debug(1, "cdr record no longer in any queue, so lets free it\n");
ast_cdr_free(cdr);
@@ -1111,7 +1125,7 @@
static void *do_cdr(void *data)
{
- struct ast_cdr_beitem *i = data;
+ struct ast_cdr_backend *i = data;
struct ast_cdr *next = NULL, *cdr = NULL;
struct timespec ts;
struct timeval tv;
@@ -1142,7 +1156,7 @@
ast_debug(1, "writing cdr to %s\n", i->name);
for (;;)
{
- be_res = i->be(cdr, i->be_data);
+ be_res = i->be(cdr, i->config);
if (be_res == AST_CDR_POST_OK) {
ast_debug(1, "cdr insert into %s ok!\n", i->name);
break;
@@ -1178,7 +1192,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 ast_cdr_backend *backend = NULL;
switch (cmd) {
case CLI_INIT:
@@ -1194,9 +1208,9 @@
if (a->argc > 3)
return CLI_SHOWUSAGE;
-
/* What if there are no backends? */
- ast_cli(a->fd, "\nCall Detail Recording (CDR) Status\n");
+ ast_cli(a->fd, "\n");
+ ast_cli(a->fd, "Call Detail Recording (CDR) Status\n");
ast_cli(a->fd, "----------------------------------\n");
ast_cli(a->fd, " Engine status: %s\n", enabled ? "Enabled" : "Disabled");
@@ -1205,20 +1219,20 @@
ast_cli(a->fd, " Safe shutdown: %s\n\n", safeshutdown ? "Enabled" : "Disabled");
ast_cli(a->fd, " CDR output unanswered calls: %s\n\n", unanswered ? "yes" : "no");
ast_cli(a->fd, " Registered Backends:\n");
- ast_cli(a->fd, " --------------------\n");
- AST_RWLIST_RDLOCK(&be_list);
- AST_RWLIST_TRAVERSE(&be_list, beitem, list) {
- if (ast_strlen_zero(beitem->name_detail)) {
- ast_cli(a->fd, " %s\n", beitem->desc);
+ ast_cli(a->fd, " --------------------\n");
+ AST_RWLIST_RDLOCK(&backends);
+ AST_RWLIST_TRAVERSE(&backends, backend, list) {
+ if (ast_strlen_zero(backend->sink_name)) {
+ ast_cli(a->fd, " %s\n", backend->description);
} else {
- ast_cli(a->fd, " %s (%s)\n", beitem->desc, beitem->name_detail);
- }
- }
- AST_RWLIST_UNLOCK(&be_list);
+ ast_cli(a->fd, " %s (%s)\n", backend->description, backend->sink_name);
+ }
+ }
+ AST_RWLIST_UNLOCK(&backends);
}
ast_cli(a->fd, "\n");
- return CLI_SUCCESS;
+ return CLI_SUCCESS;
}
static char *handle_cli_status_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -1315,37 +1329,60 @@
return do_reload(0);
}
+static void ast_cdr_backend_free(struct ast_cdr_backend *backend)
+{
+ if (!backend) {
+ return;
+ }
+
+ backend->cancel_thread = 1;
+
+ /* Signal the thread so it can exit */
+ ast_verb(2, "Signalling conditions\n");
+ ast_cond_signal(&backend->cdr_pending_cond);
+ ast_cond_signal(&backend->cdr_retry_cond);
+
+ /* Wait for our thread to exit */
+ ast_verb(2, "Joining thread\n");
+ pthread_join(backend->cdr_thread, NULL);
+ backend->cdr_thread = AST_PTHREADT_NULL;
+
+ ast_verb(2, "Destroy Pending Condition\n");
+ ast_cond_destroy(&backend->cdr_pending_cond);
+ ast_verb(2, "Destroy Retry Condition\n");
+ ast_cond_destroy(&backend->cdr_retry_cond);
+
+ /* Clean up sink data */
+ if (backend->cleanup) {
+ backend->cleanup(backend->config);
+ }
+
+ /* Clean up our stringfields and free us */
+ ast_verb(2, "Free memory\n");
+ ast_string_field_free_memory(backend);
+ ast_free(backend);
+
+ return;
+}
+
+
/* \note This actually gets called a couple of times at shutdown. Once, before we start
hanging up channels, and then again, after the channel hangup timeout expires */
void ast_cdr_engine_term(void)
{
- struct ast_cdr_beitem *i = NULL;
+ struct ast_cdr_backend *backend = NULL;
if (safeshutdown) {
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Waiting for CDR Backends to shutdown..\n");
- AST_RWLIST_WRLOCK(&be_list);
- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&be_list, i, list) {
- i->cancel_thread = 1;
- /* signal the thread so it can exit */
- ast_cond_signal(&i->cdr_pending_cond);
- ast_cond_signal(&i->cdr_retry_cond);
- /* wait for thread to exit so we can clean up */
- ast_verbose(VERBOSE_PREFIX_2 "joining thread\n");
- pthread_join(i->cdr_thread, NULL);
- ast_verbose(VERBOSE_PREFIX_2 "=ast\n");
- i->cdr_thread = AST_PTHREADT_NULL;
- ast_verbose(VERBOSE_PREFIX_2 "destroy 1\n");
- ast_cond_destroy(&i->cdr_pending_cond);
- ast_verbose(VERBOSE_PREFIX_2 "destroy 2\n");
- ast_cond_destroy(&i->cdr_retry_cond);
- ast_verbose(VERBOSE_PREFIX_2 "remove\n");
+ ast_verb(2, "Waiting for CDR Backends to shutdown...\n");
+ AST_RWLIST_WRLOCK(&backends);
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&backends, backend, list) {
AST_RWLIST_REMOVE_CURRENT(list);
- ast_verbose(VERBOSE_PREFIX_2 "ast_free\n");
- ast_free(i);
+ ast_cdr_backend_free(backend);
+ backend = NULL;
}
AST_RWLIST_TRAVERSE_SAFE_END;
- AST_RWLIST_UNLOCK(&be_list);
+ AST_RWLIST_UNLOCK(&backends);
+ ast_verb(2, "Done shutting down CDR Backends.\n");
}
}
More information about the asterisk-commits
mailing list