[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