mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 03:50:31 +00:00
Fix race condition for CEL LINKEDID_END event
This patch fixes to situations that could cause the CEL LINKEDID_END event to be missed. 1) During a core stop gracefully, modules are unloaded when ast_active_channels == 0. The LINKDEDID_END event fires during the channel destructor. This means that occasionally, the cel_* module will be unloaded before the channel is destroyed. It seemed generally useful to wait until the refcount of all channels == 0 before unloading, so I added a channel counter and used it in the shutdown code. 2) During a masquerade, ast_channel_change_linkedid is called. It calls ast_cel_check_retire_linkedid which unrefs the linkedid in the linkedids container in cel.c. It didn't ref the new linkedid. Now it does. Review: https://reviewboard.asterisk.org/r/1900/ ........ Merged revisions 367292 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 367299 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@367309 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
43
main/cel.c
43
main/cel.c
@@ -470,6 +470,31 @@ struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event
|
||||
return tchan;
|
||||
}
|
||||
|
||||
int ast_cel_linkedid_ref(const char *linkedid)
|
||||
{
|
||||
char *lid;
|
||||
|
||||
if (ast_strlen_zero(linkedid)) {
|
||||
ast_log(LOG_ERROR, "The linkedid should never be empty\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(lid = ao2_find(linkedids, (void *) linkedid, OBJ_POINTER))) {
|
||||
if (!(lid = ao2_alloc(strlen(linkedid) + 1, NULL))) {
|
||||
return -1;
|
||||
}
|
||||
strcpy(lid, linkedid);
|
||||
if (!ao2_link(linkedids, lid)) {
|
||||
ao2_ref(lid, -1);
|
||||
return -1;
|
||||
}
|
||||
/* Leave both the link and the alloc refs to show a count of 1 + the link */
|
||||
}
|
||||
/* If we've found, go ahead and keep the ref to increment count of how many channels
|
||||
* have this linkedid. We'll clean it up in check_retire */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
|
||||
const char *userdefevname, const char *extra, struct ast_channel *peer2)
|
||||
{
|
||||
@@ -487,22 +512,10 @@ int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event
|
||||
/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
|
||||
* reporting on CHANNEL_START so we can track when to send LINKEDID_END */
|
||||
if (cel_enabled && ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
|
||||
char *lid;
|
||||
if (!(lid = ao2_find(linkedids, (void *) linkedid, OBJ_POINTER))) {
|
||||
if (!(lid = ao2_alloc(strlen(linkedid) + 1, NULL))) {
|
||||
ast_mutex_unlock(&reload_lock);
|
||||
return -1;
|
||||
}
|
||||
strcpy(lid, linkedid);
|
||||
if (!ao2_link(linkedids, lid)) {
|
||||
ao2_ref(lid, -1);
|
||||
ast_mutex_unlock(&reload_lock);
|
||||
return -1;
|
||||
}
|
||||
/* Leave both the link and the alloc refs to show a count of 1 + the link */
|
||||
if (ast_cel_linkedid_ref(linkedid)) {
|
||||
ast_mutex_unlock(&reload_lock);
|
||||
return -1;
|
||||
}
|
||||
/* If we've found, go ahead and keep the ref to increment count of how many channels
|
||||
* have this linkedid. We'll clean it up in check_retire */
|
||||
}
|
||||
|
||||
if (!cel_enabled || !ast_cel_track_event(event_type)) {
|
||||
|
Reference in New Issue
Block a user