main/cdr: Allow modules to modify CDR fields before dispatching them

This patch adds the functions

	ast_cdr_modifier_register()
	ast_cdr_modifier_unregister()

That work much like ast_cdr_register() and ast_cdr_unregister().

Modules registered will be given a chance to modify (or to do whatever
they want) CDR fields just before they are passed to registered engines.

Thus, for instance, if a module change the "userfield" field of a CDR,
the modified value will be passed to every registered CDR backend for
logging.

ASTERISK-25479 #close

Change-Id: If11d8fd19ef89b1a66ecacf1201e10fcf86ccd56
changes/50/1450/3
Jonh Wendell 10 years ago committed by Joshua Colp
parent b19860c03a
commit 77780790e0

@ -535,6 +535,36 @@ int ast_cdr_backend_suspend(const char *name);
*/
int ast_cdr_backend_unsuspend(const char *name);
/*!
* \brief Register a CDR modifier
* \param name name associated with the particular CDR modifier
* \param desc description of the CDR modifier
* \param be function pointer to a CDR modifier
*
* Used to register a Call Detail Record modifier.
*
* This gives modules a chance to modify CDR fields before they are dispatched
* to registered backends (odbc, syslog, etc).
*
* \note The *modified* CDR will be passed to **all** registered backends for
* logging. For instance, if cdr_manager changes the CDR data, cdr_adaptive_odbc
* will also get the modified CDR.
*
* \retval 0 on success.
* \retval -1 on error
*/
int ast_cdr_modifier_register(const char *name, const char *desc, ast_cdrbe be);
/*!
* \brief Unregister a CDR modifier
* \param name name of CDR modifier to unregister
* Unregisters a CDR modifier by its name
*
* \retval 0 The modifier unregistered successfully
* \retval -1 The modifier could not be unregistered at this time
*/
int ast_cdr_modifier_unregister(const char *name);
/*!
* \brief Disposition to a string
* \param disposition input binary form

@ -297,6 +297,9 @@ struct cdr_beitem {
/*! \brief List of registered backends */
static AST_RWLIST_HEAD_STATIC(be_list, cdr_beitem);
/*! \brief List of registered modifiers */
static AST_RWLIST_HEAD_STATIC(mo_list, cdr_beitem);
/*! \brief Queued CDR waiting to be batched */
struct cdr_batch_item {
struct ast_cdr *cdr;
@ -2678,7 +2681,7 @@ int ast_cdr_backend_unsuspend(const char *name)
return success;
}
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
static int cdr_generic_register(struct be_list *generic_list, const char *name, const char *desc, ast_cdrbe be)
{
struct cdr_beitem *i = NULL;
@ -2690,11 +2693,11 @@ int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
return -1;
}
AST_RWLIST_WRLOCK(&be_list);
AST_RWLIST_TRAVERSE(&be_list, i, list) {
AST_RWLIST_WRLOCK(generic_list);
AST_RWLIST_TRAVERSE(generic_list, i, list) {
if (!strcasecmp(name, i->name)) {
ast_log(LOG_WARNING, "Already have a CDR backend called '%s'\n", name);
AST_RWLIST_UNLOCK(&be_list);
AST_RWLIST_UNLOCK(generic_list);
return -1;
}
}
@ -2706,40 +2709,50 @@ int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
ast_copy_string(i->name, name, sizeof(i->name));
ast_copy_string(i->desc, desc, sizeof(i->desc));
AST_RWLIST_INSERT_HEAD(&be_list, i, list);
AST_RWLIST_UNLOCK(&be_list);
AST_RWLIST_INSERT_HEAD(generic_list, i, list);
AST_RWLIST_UNLOCK(generic_list);
return 0;
}
int ast_cdr_unregister(const char *name)
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
{
return cdr_generic_register(&be_list, name, desc, be);
}
int ast_cdr_modifier_register(const char *name, const char *desc, ast_cdrbe be)
{
return cdr_generic_register((struct be_list *)&mo_list, name, desc, be);
}
static int ast_cdr_generic_unregister(struct be_list *generic_list, const char *name)
{
struct cdr_beitem *match = NULL;
int active_count;
AST_RWLIST_WRLOCK(&be_list);
AST_RWLIST_TRAVERSE(&be_list, match, list) {
AST_RWLIST_WRLOCK(generic_list);
AST_RWLIST_TRAVERSE(generic_list, match, list) {
if (!strcasecmp(name, match->name)) {
break;
}
}
if (!match) {
AST_RWLIST_UNLOCK(&be_list);
AST_RWLIST_UNLOCK(generic_list);
return 0;
}
active_count = ao2_container_count(active_cdrs_by_channel);
if (!match->suspended && active_count != 0) {
AST_RWLIST_UNLOCK(&be_list);
AST_RWLIST_UNLOCK(generic_list);
ast_log(AST_LOG_WARNING, "Unable to unregister CDR backend %s; %d CDRs are still active\n",
name, active_count);
return -1;
}
AST_RWLIST_REMOVE(&be_list, match, list);
AST_RWLIST_UNLOCK(&be_list);
AST_RWLIST_REMOVE(generic_list, match, list);
AST_RWLIST_UNLOCK(generic_list);
ast_verb(2, "Unregistered '%s' CDR backend\n", name);
ast_free(match);
@ -2747,6 +2760,16 @@ int ast_cdr_unregister(const char *name)
return 0;
}
int ast_cdr_unregister(const char *name)
{
return ast_cdr_generic_unregister(&be_list, name);
}
int ast_cdr_modifier_unregister(const char *name)
{
return ast_cdr_generic_unregister((struct be_list *)&mo_list, name);
}
struct ast_cdr *ast_cdr_dup(struct ast_cdr *cdr)
{
struct ast_cdr *newcdr;
@ -3262,6 +3285,13 @@ static void post_cdr(struct ast_cdr *cdr)
continue;
}
/* Modify CDR's */
AST_RWLIST_RDLOCK(&mo_list);
AST_RWLIST_TRAVERSE(&mo_list, i, list) {
i->be(cdr);
}
AST_RWLIST_UNLOCK(&mo_list);
if (ast_test_flag(cdr, AST_CDR_FLAG_DISABLE)) {
continue;
}

Loading…
Cancel
Save