From: Jonh Wendell Date: Mon, 19 Oct 2015 19:14:32 +0000 (-0200) Subject: main/cdr: Allow modules to modify CDR fields before dispatching them X-Git-Tag: 14.0.0-beta1~629^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77780790e0fa646c15260f4ae4e958e33913bfed;p=thirdparty%2Fasterisk.git 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 --- diff --git a/include/asterisk/cdr.h b/include/asterisk/cdr.h index 5654c3847f..f752f7f9fc 100644 --- a/include/asterisk/cdr.h +++ b/include/asterisk/cdr.h @@ -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 diff --git a/main/cdr.c b/main/cdr.c index 8d7f53f174..5e24075029 100644 --- a/main/cdr.c +++ b/main/cdr.c @@ -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; }