From 8e8b329e14ad2e4d747c4c4eb33c118305401aee Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Tue, 3 Dec 2013 17:07:29 +0000 Subject: Add channel locking for channel snapshot creation. This adds channel locks around calls to create channel snapshots as well as other functions which operate on a channel and then end up creating a channel snapshot. Functions that expect the channel to be locked prior to being called have had their documentation updated to indicate such. ........ Merged revisions 403311 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403314 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- addons/chan_mobile.c | 2 ++ addons/chan_ooh323.c | 2 +- apps/app_agent_pool.c | 4 ++++ apps/app_confbridge.c | 2 ++ apps/app_dial.c | 16 ++++++++++++--- apps/app_disa.c | 5 ++++- apps/app_meetme.c | 2 ++ apps/app_queue.c | 13 +++++++++++- apps/app_userevent.c | 2 ++ apps/app_voicemail.c | 5 ++++- channels/chan_alsa.c | 2 ++ channels/chan_console.c | 2 ++ channels/chan_dahdi.c | 8 ++++++++ channels/chan_gtalk.c | 4 ++++ channels/chan_h323.c | 4 ++++ channels/chan_iax2.c | 7 +++++++ channels/chan_jingle.c | 4 ++++ channels/chan_mgcp.c | 4 ++++ channels/chan_misdn.c | 14 +++++++++++++ channels/chan_motif.c | 4 ++++ channels/chan_nbs.c | 2 ++ channels/chan_oss.c | 2 ++ channels/chan_phone.c | 2 ++ channels/chan_pjsip.c | 13 ++++++++---- channels/chan_sip.c | 2 +- channels/chan_skinny.c | 4 ++++ channels/chan_unistim.c | 6 +++++- channels/chan_vpb.cc | 2 ++ channels/sig_analog.c | 4 ++++ channels/sig_pri.c | 2 ++ funcs/func_timeout.c | 2 ++ include/asterisk/aoc.h | 5 ++++- include/asterisk/channel.h | 38 +++++++++++++++++++++++++++++++---- include/asterisk/channelstate.h | 5 ++++- include/asterisk/stasis_bridges.h | 21 +++++++++++++++++++ include/asterisk/stasis_channels.h | 16 +++++++++++++++ main/bridge.c | 9 ++++++++- main/bridge_channel.c | 11 ++++++++++ main/cel.c | 2 ++ main/channel.c | 18 +++++++++++++++++ main/core_local.c | 26 +++++++++++++++--------- main/core_unreal.c | 4 ++++ main/dial.c | 2 ++ main/endpoints.c | 2 ++ main/pbx.c | 12 +++++++++++ main/pickup.c | 10 +++++++-- main/stasis_bridges.c | 6 ++++++ main/stasis_channels.c | 4 ++++ pbx/pbx_realtime.c | 2 ++ res/parking/parking_bridge_features.c | 2 ++ res/parking/parking_manager.c | 4 ++++ res/res_agi.c | 12 +++++++++++ res/res_pjsip_refer.c | 2 ++ res/res_stasis.c | 4 ++++ tests/test_cdr.c | 33 ++++++++++++++++++++++++++++++ tests/test_cel.c | 6 ++++++ tests/test_stasis_channels.c | 12 +++++++++++ 57 files changed, 384 insertions(+), 31 deletions(-) diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c index 2cf7c7dbd..c9e56b854 100644 --- a/addons/chan_mobile.c +++ b/addons/chan_mobile.c @@ -861,6 +861,7 @@ static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num goto e_return; } + ast_channel_lock(chn); ast_channel_tech_set(chn, &mbl_tech); ast_format_cap_add(ast_channel_nativeformats(chn), &prefformat); ast_format_copy(ast_channel_rawreadformat(chn), &prefformat); @@ -878,6 +879,7 @@ static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num if (pvt->sco_socket != -1) { ast_channel_set_fd(chn, 0, pvt->sco_socket); } + ast_channel_unlock(chn); return chn; diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c index 56a1b7b68..deec21fa7 100644 --- a/addons/chan_ooh323.c +++ b/addons/chan_ooh323.c @@ -2153,8 +2153,8 @@ int onCallEstablished(ooCallData *call) } ast_queue_control(c, AST_CONTROL_ANSWER); - ast_channel_unlock(p->owner); ast_publish_channel_state(c); + ast_channel_unlock(p->owner); } ast_mutex_unlock(&p->lock); diff --git a/apps/app_agent_pool.c b/apps/app_agent_pool.c index c968153e6..d49ec2348 100644 --- a/apps/app_agent_pool.c +++ b/apps/app_agent_pool.c @@ -1464,7 +1464,9 @@ static void agent_logout(struct agent_pvt *agent) ast_bridge_destroy(caller_bridge, AST_CAUSE_USER_BUSY); } + ast_channel_lock(logged); send_agent_logoff(logged, agent->username, time_logged_in); + ast_channel_unlock(logged); ast_verb(2, "Agent '%s' logged out. Logged in for %ld seconds.\n", agent->username, time_logged_in); ast_channel_unref(logged); @@ -2045,7 +2047,9 @@ static int agent_login_exec(struct ast_channel *chan, const char *data) ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", agent->username, ast_getformatname(ast_channel_readformat(chan)), ast_getformatname(ast_channel_writeformat(chan))); + ast_channel_lock(chan); send_agent_login(chan, agent->username); + ast_channel_unlock(chan); agent_run(agent, chan); return -1; diff --git a/apps/app_confbridge.c b/apps/app_confbridge.c index 8347bc6ed..a886b5876 100644 --- a/apps/app_confbridge.c +++ b/apps/app_confbridge.c @@ -1368,7 +1368,9 @@ static int alloc_playback_chan(struct confbridge_conference *conference) } /* To make sure playback_chan has the same language of that profile */ + ast_channel_lock(conference->playback_chan); ast_channel_language_set(conference->playback_chan, conference->b_profile.language); + ast_channel_unlock(conference->playback_chan); ast_debug(1, "Created announcer channel '%s' to conference bridge '%s'\n", ast_channel_name(conference->playback_chan), conference->name); diff --git a/apps/app_dial.c b/apps/app_dial.c index c9bee19b0..c52a9b917 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -2104,6 +2104,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast struct ast_party_caller caller; /* Reset all DIAL variables back to blank, to prevent confusion (in case we don't reset all of them). */ + ast_channel_lock(chan); ast_channel_stage_snapshot(chan); pbx_builtin_setvar_helper(chan, "DIALSTATUS", ""); pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", ""); @@ -2111,6 +2112,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", ""); pbx_builtin_setvar_helper(chan, "DIALEDTIME", ""); ast_channel_stage_snapshot_done(chan); + ast_channel_unlock(chan); if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n"); @@ -2443,15 +2445,17 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast continue; } + ast_channel_lock(tc); ast_channel_stage_snapshot(tc); + ast_channel_unlock(tc); ast_channel_get_device_name(tc, device_name, sizeof(device_name)); if (!ignore_cc) { ast_cc_extension_monitor_add_dialstring(chan, tmp->interface, device_name); } - pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", tmp->number); ast_channel_lock_both(tc, chan); + pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", tmp->number); /* Setup outgoing SDP to match incoming one */ if (!AST_LIST_FIRST(&out_chans) && !rest && CAN_EARLY_BRIDGE(peerflags, chan, tc)) { @@ -2724,8 +2728,10 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast number = ast_strdupa(number); } ast_channel_unlock(peer); + ast_channel_lock(chan); pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number); ast_channel_stage_snapshot_done(chan); + ast_channel_unlock(chan); if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) { ast_debug(1, "app_dial: sendurl=%s.\n", args.url); @@ -2811,16 +2817,18 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast /* chan and peer are going into the PBX; as such neither are considered * outgoing channels any longer */ ast_clear_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING); - ast_channel_stage_snapshot(peer); - ast_clear_flag(ast_channel_flags(peer), AST_FLAG_OUTGOING); ast_replace_subargument_delimiter(opt_args[OPT_ARG_GOTO]); ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]); /* peer goes to the same context and extension as chan, so just copy info from chan*/ + ast_channel_lock(peer); + ast_channel_stage_snapshot(peer); + ast_clear_flag(ast_channel_flags(peer), AST_FLAG_OUTGOING); ast_channel_context_set(peer, ast_channel_context(chan)); ast_channel_exten_set(peer, ast_channel_exten(chan)); ast_channel_priority_set(peer, ast_channel_priority(chan) + 2); ast_channel_stage_snapshot_done(peer); + ast_channel_unlock(peer); if (ast_pbx_start(peer)) { ast_autoservice_chan_hangup_peer(chan, peer); } @@ -2970,7 +2978,9 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast if (!res) { if (!ast_tvzero(calldurationlimit)) { struct timeval whentohangup = ast_tvadd(ast_tvnow(), calldurationlimit); + ast_channel_lock(peer); ast_channel_whentohangup_set(peer, &whentohangup); + ast_channel_unlock(peer); } if (!ast_strlen_zero(dtmfcalled)) { ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled); diff --git a/apps/app_disa.c b/apps/app_disa.c index fe53772f1..9e7412717 100644 --- a/apps/app_disa.c +++ b/apps/app_disa.c @@ -381,8 +381,11 @@ static int disa_exec(struct ast_channel *chan, const char *data) ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum); } - if (!ast_strlen_zero(acctcode)) + if (!ast_strlen_zero(acctcode)) { + ast_channel_lock(chan); ast_channel_accountcode_set(chan, acctcode); + ast_channel_unlock(chan); + } if (special_noanswer) { ast_clear_flag(&cdr_flags, AST_CDR_FLAG_DISABLE); diff --git a/apps/app_meetme.c b/apps/app_meetme.c index ffd55e70d..d9bdeb605 100644 --- a/apps/app_meetme.c +++ b/apps/app_meetme.c @@ -1384,7 +1384,9 @@ static void meetme_stasis_generate_msg(struct ast_conference *meetme_conference, } } + ast_channel_lock(chan); msg = ast_channel_blob_create(chan, message_type, json_object); + ast_channel_unlock(chan); if (!msg) { return; diff --git a/apps/app_queue.c b/apps/app_queue.c index 906dff15f..713dba2d7 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -2040,8 +2040,12 @@ static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup); + ast_channel_lock(caller); caller_snapshot = ast_channel_snapshot_create(caller); + ast_channel_unlock(caller); + ast_channel_lock(agent); agent_snapshot = ast_channel_snapshot_create(agent); + ast_channel_unlock(agent); if (!caller_snapshot || !agent_snapshot) { return; @@ -3452,7 +3456,9 @@ static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result * "Queue", q->name, "Position", qe->pos, "Count", q->count); + ast_channel_lock(qe->chan); ast_channel_publish_blob(qe->chan, queue_caller_join_type(), blob); + ast_channel_unlock(qe->chan); ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos ); } ao2_unlock(q); @@ -3731,7 +3737,9 @@ static void leave_queue(struct queue_ent *qe) "Queue", q->name, "Position", qe->pos, "Count", q->count); + ast_channel_lock(qe->chan); ast_channel_publish_blob(qe->chan, queue_caller_leave_type(), blob); + ast_channel_unlock(qe->chan); ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan)); /* Take us out of the queue */ if (prev) { @@ -4329,10 +4337,13 @@ static void record_abandoned(struct queue_ent *qe) "Position", qe->pos, "OriginalPosition", qe->opos, "HoldTime", (int)(time(NULL) - qe->start)); - ast_channel_publish_blob(qe->chan, queue_caller_abandon_type(), blob); qe->parent->callsabandoned++; ao2_unlock(qe->parent); + + ast_channel_lock(qe->chan); + ast_channel_publish_blob(qe->chan, queue_caller_abandon_type(), blob); + ast_channel_unlock(qe->chan); } /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */ diff --git a/apps/app_userevent.c b/apps/app_userevent.c index e0dafbb9f..f5defd49d 100644 --- a/apps/app_userevent.c +++ b/apps/app_userevent.c @@ -114,7 +114,9 @@ static int userevent_exec(struct ast_channel *chan, const char *data) } } + ast_channel_lock(chan); ast_channel_publish_blob(chan, ast_channel_user_event_type(), blob); + ast_channel_unlock(chan); return 0; } diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index dca4eceee..7abf4530e 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -10958,8 +10958,11 @@ static int vm_execmain(struct ast_channel *chan, const char *data) #endif /* Set language from config to override channel language */ - if (!ast_strlen_zero(vmu->language)) + if (!ast_strlen_zero(vmu->language)) { + ast_channel_lock(chan); ast_channel_language_set(chan, vmu->language); + ast_channel_unlock(chan); + } /* Retrieve urgent, old and new message counts */ ast_debug(1, "Before open_mailbox\n"); diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c index 60bbacbb8..065eff551 100644 --- a/channels/chan_alsa.c +++ b/channels/chan_alsa.c @@ -581,6 +581,7 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const ch if (!(tmp = ast_channel_alloc(1, state, 0, 0, "", p->exten, p->context, linkedid, 0, "ALSA/%s", indevname))) return NULL; + ast_channel_lock(tmp); ast_channel_stage_snapshot(tmp); ast_channel_tech_set(tmp, &alsa_tech); @@ -601,6 +602,7 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const ch ast_jb_configure(tmp, &global_jbconf); ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { diff --git a/channels/chan_console.c b/channels/chan_console.c index 922c53b42..6f694c2c9 100644 --- a/channels/chan_console.c +++ b/channels/chan_console.c @@ -428,6 +428,7 @@ static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, return NULL; } + ast_channel_lock(chan); ast_channel_stage_snapshot(chan); ast_channel_tech_set(chan, &console_tech); @@ -444,6 +445,7 @@ static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext, ast_jb_configure(chan, &global_jbconf); ast_channel_stage_snapshot_done(chan); + ast_channel_unlock(chan); if (state != AST_STATE_DOWN) { if (ast_pbx_start(chan)) { diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 2eba958a8..843254c56 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -1667,7 +1667,9 @@ static void publish_dahdichannel(struct ast_channel *chan, int span, const char return; } + ast_channel_lock(chan); ast_channel_publish_blob(chan, dahdichannel_type(), blob); + ast_channel_unlock(chan); } /*! @@ -8916,6 +8918,7 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb return NULL; } + ast_channel_lock(tmp); ast_channel_stage_snapshot(tmp); if (callid) { @@ -9096,6 +9099,7 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb pbx_builtin_setvar_helper(tmp, v->name, v->value); ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); ast_module_ref(ast_module_info->self); @@ -9614,6 +9618,7 @@ static void *analog_ss_thread(void *data) getforward = 0; } else { res = tone_zone_play_tone(p->subs[idx].dfd, -1); + ast_channel_lock(chan); ast_channel_exten_set(chan, exten); if (!ast_strlen_zero(p->cid_num)) { if (!p->hidecallerid) @@ -9626,6 +9631,7 @@ static void *analog_ss_thread(void *data) ast_set_callerid(chan, NULL, p->cid_name, NULL); } ast_setstate(chan, AST_STATE_RING); + ast_channel_unlock(chan); dahdi_ec_enable(p); res = ast_pbx_run(chan); if (res) { @@ -10389,8 +10395,10 @@ static void *analog_ss_thread(void *data) my_handle_notify_message(chan, p, flags, -1); + ast_channel_lock(chan); ast_setstate(chan, AST_STATE_RING); ast_channel_rings_set(chan, 1); + ast_channel_unlock(chan); p->ringt = p->ringt_base; res = ast_pbx_run(chan); if (res) { diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c index d6a094941..72c01ac8d 100644 --- a/channels/chan_gtalk.c +++ b/channels/chan_gtalk.c @@ -1150,6 +1150,7 @@ static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, return NULL; } + ast_channel_lock(tmp); ast_channel_stage_snapshot(tmp); ast_channel_tech_set(tmp, >alk_tech); @@ -1226,6 +1227,7 @@ static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i, ast_jb_configure(tmp, &global_jbconf); ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp)); @@ -1419,7 +1421,9 @@ static int gtalk_newcall(struct gtalk *client, ikspak *pak) ast_format_cap_joint_copy(p->cap, p->peercap, p->jointcap); ast_mutex_unlock(&p->lock); + ast_channel_lock(chan); ast_setstate(chan, AST_STATE_RING); + ast_channel_unlock(chan); if (ast_format_cap_is_empty(p->jointcap)) { ast_log(LOG_WARNING, "Capabilities don't match : us - %s, peer - %s, combined - %s \n", ast_getformatname_multiple(s1, BUFSIZ, p->cap), ast_getformatname_multiple(s2, BUFSIZ, p->peercap), diff --git a/channels/chan_h323.c b/channels/chan_h323.c index 22dba3c18..7ce098415 100644 --- a/channels/chan_h323.c +++ b/channels/chan_h323.c @@ -1061,6 +1061,9 @@ static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const c ch = ast_channel_alloc(1, state, cid_num, cid_name, pvt->accountcode, pvt->exten, pvt->context, linkedid, pvt->amaflags, "H323/%s", host); /* Update usage counter */ ast_module_ref(ast_module_info->self); + if (ch) { + ast_channel_lock(ch); + } ast_mutex_lock(&pvt->lock); if (ch) { ast_channel_tech_set(ch, &oh323_tech); @@ -1139,6 +1142,7 @@ static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const c } if (pvt->cd.transfer_capability >= 0) ast_channel_transfercapability_set(ch, pvt->cd.transfer_capability); + ast_channel_unlock(ch); if (state != AST_STATE_DOWN) { if (ast_pbx_start(ch)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(ch)); diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index e27cc14c6..80081174e 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -5689,11 +5689,15 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab /* Don't hold call lock */ ast_mutex_unlock(&iaxsl[callno]); tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, linkedid, i->amaflags, "IAX2/%s-%d", i->host, i->callno); + if (tmp) { + ast_channel_lock(tmp); + } ast_mutex_lock(&iaxsl[callno]); if (i != iaxs[callno]) { if (tmp) { /* unlock and relock iaxsl[callno] to preserve locking order */ ast_mutex_unlock(&iaxsl[callno]); + ast_channel_unlock(tmp); tmp = ast_channel_release(tmp); ast_mutex_lock(&iaxsl[callno]); } @@ -5803,6 +5807,7 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab } ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { @@ -12234,7 +12239,9 @@ static struct ast_channel *iax2_request(const char *type, struct ast_format_cap if (c) { struct ast_format_cap *joint; if (callid) { + ast_channel_lock(c); ast_channel_callid_set(c, callid); + ast_channel_unlock(c); } /* Choose a format we can live with */ diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c index 56c15b193..8604d4eb9 100644 --- a/channels/chan_jingle.c +++ b/channels/chan_jingle.c @@ -864,6 +864,7 @@ static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt * return NULL; } + ast_channel_lock(tmp); ast_channel_stage_snapshot(tmp); ast_channel_tech_set(tmp, &jingle_tech); @@ -941,6 +942,7 @@ static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt * ast_jb_configure(tmp, &global_jbconf); ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp)); @@ -1115,7 +1117,9 @@ static int jingle_newcall(struct jingle *client, ikspak *pak) } ast_mutex_unlock(&p->lock); + ast_channel_lock(chan); ast_setstate(chan, AST_STATE_RING); + ast_channel_unlock(chan); res = ast_pbx_start(chan); switch (res) { diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 84fb3b225..c10697158 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -1507,6 +1507,7 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state, cons tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, linkedid, i->accountcode, i->exten, i->context, i->amaflags, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id); if (tmp) { + ast_channel_lock(tmp); ast_channel_stage_snapshot(tmp); ast_channel_tech_set(tmp, &mgcp_tech); ast_format_cap_copy(ast_channel_nativeformats(tmp), i->cap); @@ -1570,6 +1571,7 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state, cons } ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { @@ -3046,6 +3048,7 @@ static void *mgcp_ss(void *data) } else { /*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/ ast_indicate(chan, -1); + ast_channel_lock(chan); ast_channel_exten_set(chan, p->dtmf_buf); ast_channel_dialed(chan)->number.str = ast_strdup(p->dtmf_buf); memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf)); @@ -3054,6 +3057,7 @@ static void *mgcp_ss(void *data) p->hidecallerid ? "" : p->cid_name, ast_channel_caller(chan)->ani.number.valid ? NULL : p->cid_num); ast_setstate(chan, AST_STATE_RING); + ast_channel_unlock(chan); if (p->dtmfmode & MGCP_DTMF_HYBRID) { p->dtmfmode |= MGCP_DTMF_INBAND; ast_indicate(chan, -1); diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c index 38197c638..a1b9105e6 100644 --- a/channels/chan_misdn.c +++ b/channels/chan_misdn.c @@ -5954,7 +5954,9 @@ static int read_config(struct chan_list *ch) chan_misdn_log(1, port, "read_config: Getting Config\n"); misdn_cfg_get(port, MISDN_CFG_LANGUAGE, lang, sizeof(lang)); + ast_channel_lock(ast); ast_channel_language_set(ast, lang); + ast_channel_unlock(ast); misdn_cfg_get(port, MISDN_CFG_MUSICCLASS, ch->mohinterpret, sizeof(ch->mohinterpret)); @@ -6000,7 +6002,9 @@ static int read_config(struct chan_list *ch) misdn_cfg_get(bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context)); + ast_channel_lock(ast); ast_channel_context_set(ast, ch->context); + ast_channel_unlock(ast); #ifdef MISDN_1_2 update_pipeline_config(bc); @@ -6017,8 +6021,10 @@ static int read_config(struct chan_list *ch) misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg)); misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg)); chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg)); + ast_channel_lock(ast); ast_channel_pickupgroup_set(ast, pg); ast_channel_callgroup_set(ast, cg); + ast_channel_unlock(ast); misdn_cfg_get(port, MISDN_CFG_NAMEDPICKUPGROUP, &npg, sizeof(npg)); misdn_cfg_get(port, MISDN_CFG_NAMEDCALLGROUP, &ncg, sizeof(ncg)); @@ -6031,8 +6037,10 @@ static int read_config(struct chan_list *ch) ast_free(tmp_str); } + ast_channel_lock(ast); ast_channel_named_pickupgroups_set(ast, npg); ast_channel_named_callgroups_set(ast, ncg); + ast_channel_unlock(ast); if (ch->originator == ORG_AST) { char callerid[BUFFERSIZE + 1]; @@ -6086,7 +6094,9 @@ static int read_config(struct chan_list *ch) /* Add configured prefix to dialed.number */ misdn_add_number_prefix(bc->port, bc->dialed.number_type, bc->dialed.number, sizeof(bc->dialed.number)); + ast_channel_lock(ast); ast_channel_exten_set(ast, bc->dialed.number); + ast_channel_unlock(ast); misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial)); ast_mutex_init(&ch->overlap_tv_lock); @@ -10228,8 +10238,10 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) export_ch(chan, bc, ch); + ast_channel_lock(ch->ast); ast_channel_rings_set(ch->ast, 1); ast_setstate(ch->ast, AST_STATE_RINGING); + ast_channel_unlock(ch->ast); /* Update asterisk channel caller information */ chan_misdn_log(2, bc->port, " --> TON: %s(%d)\n", misdn_to_str_ton(bc->caller.number_type), bc->caller.number_type); @@ -10528,7 +10540,9 @@ cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data) } ast_queue_control(ch->ast, AST_CONTROL_RINGING); + ast_channel_lock(ch->ast); ast_setstate(ch->ast, AST_STATE_RINGING); + ast_channel_unlock(ch->ast); cb_log(7, bc->port, " --> Set State Ringing\n"); diff --git a/channels/chan_motif.c b/channels/chan_motif.c index 1e7ee3cce..85234ad3a 100644 --- a/channels/chan_motif.c +++ b/channels/chan_motif.c @@ -785,6 +785,7 @@ static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct j if (!(chan = ast_channel_alloc(1, state, S_OR(title, ""), S_OR(cid_name, ""), "", "", "", linkedid, 0, "Motif/%s-%04lx", str, ast_random() & 0xffff))) { return NULL; } + ast_channel_lock(chan); ast_channel_stage_snapshot(chan); @@ -852,6 +853,7 @@ static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct j ao2_unlock(endpoint); ast_channel_stage_snapshot_done(chan); + ast_channel_unlock(chan); return chan; } @@ -2412,7 +2414,9 @@ static void jingle_action_session_initiate(struct jingle_endpoint *endpoint, str ao2_link(endpoint->state->sessions, session); + ast_channel_lock(chan); ast_setstate(chan, AST_STATE_RING); + ast_channel_unlock(chan); res = ast_pbx_start(chan); switch (res) { diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c index 1d8c59d4e..41f696207 100644 --- a/channels/chan_nbs.c +++ b/channels/chan_nbs.c @@ -223,6 +223,7 @@ static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const char *lin struct ast_channel *tmp; tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, linkedid, 0, "NBS/%s", i->stream); if (tmp) { + ast_channel_lock(tmp); ast_channel_tech_set(tmp, &nbs_tech); ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs)); @@ -239,6 +240,7 @@ static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const char *lin ast_channel_language_set(tmp, ""); i->owner = tmp; i->u = ast_module_user_add(tmp); + ast_channel_unlock(tmp); if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp)); diff --git a/channels/chan_oss.c b/channels/chan_oss.c index 5ae18f362..92c7374db 100644 --- a/channels/chan_oss.c +++ b/channels/chan_oss.c @@ -799,6 +799,7 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, c = ast_channel_alloc(1, state, o->cid_num, o->cid_name, "", ext, ctx, linkedid, 0, "Console/%s", o->device + 5); if (c == NULL) return NULL; + ast_channel_lock(c); ast_channel_tech_set(c, &oss_tech); if (o->sounddev < 0) setformat(o, O_RDWR); @@ -829,6 +830,7 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx, o->owner = c; ast_module_ref(ast_module_info->self); ast_jb_configure(c, &global_jbconf); + ast_channel_unlock(c); if (state != AST_STATE_DOWN) { if (ast_pbx_start(c)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(c)); diff --git a/channels/chan_phone.c b/channels/chan_phone.c index c1a24b8b1..ca69a2f69 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -862,6 +862,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx, struct ast_format tmpfmt; tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, "", i->ext, i->context, linkedid, 0, "Phone/%s", i->dev + 5); if (tmp) { + ast_channel_lock(tmp); ast_channel_tech_set(tmp, cur_tech); ast_channel_set_fd(tmp, 0, i->fd); /* XXX Switching formats silently causes kernel panics XXX */ @@ -898,6 +899,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx, ast_channel_caller(tmp)->ani.number.valid = 1; ast_channel_caller(tmp)->ani.number.str = ast_strdup(i->cid_num); } + ast_channel_unlock(tmp); i->owner = tmp; ast_module_ref(ast_module_info->self); diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 80cf270af..12fb45969 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -577,13 +577,15 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s return NULL; } - ast_channel_stage_snapshot(chan); - /* If res_pjsip_session is ever updated to create/destroy ast_sip_session_media * during a call such as if multiple same-type stream support is introduced, * these will need to be recaptured as well */ pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY); pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY); + + ast_channel_lock(chan); + ast_channel_stage_snapshot(chan); + ast_channel_tech_pvt_set(chan, channel); if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) { ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, ast_channel_uniqueid(chan)); @@ -632,9 +634,10 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s ast_channel_zone_set(chan, zone); } - ast_endpoint_add_channel(session->endpoint->persistent, chan); - ast_channel_stage_snapshot_done(chan); + ast_channel_unlock(chan); + + ast_endpoint_add_channel(session->endpoint->persistent, chan); return chan; } @@ -2030,9 +2033,11 @@ static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct switch (status.code) { case 180: ast_queue_control(session->channel, AST_CONTROL_RINGING); + ast_channel_lock(session->channel); if (ast_channel_state(session->channel) != AST_STATE_UP) { ast_setstate(session->channel, AST_STATE_RINGING); } + ast_channel_unlock(session->channel); break; case 183: ast_queue_control(session->channel, AST_CONTROL_PROGRESS); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index c56f7c4c9..fafe71257 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -8106,6 +8106,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit } } + ast_channel_lock(tmp); ast_channel_stage_snapshot(tmp); /* If we sent in a callid, bind it to the channel. */ @@ -8113,7 +8114,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit ast_channel_callid_set(tmp, callid); } - ast_channel_lock(tmp); sip_pvt_lock(i); ast_channel_cc_params_init(tmp, i->cc_params); ast_channel_caller(tmp)->id.tag = ast_strdup(i->cid_tag); diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index a65862ff3..191c3cc24 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -4845,6 +4845,7 @@ static void *skinny_newcall(void *data) struct skinny_device *d = l->device; int res = 0; + ast_channel_lock(c); ast_set_callerid(c, l->hidecallerid ? "" : l->cid_num, l->hidecallerid ? "" : l->cid_name, @@ -4858,6 +4859,7 @@ static void *skinny_newcall(void *data) ast_party_name_init(&ast_channel_connected(c)->id.name); #endif ast_setstate(c, AST_STATE_RING); + ast_channel_unlock(c); if (!sub->rtp) { start_rtp(sub); } @@ -5424,6 +5426,7 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli AST_LIST_INSERT_HEAD(&l->sub, sub, list); //l->activesub = sub; } + ast_channel_lock(tmp); ast_channel_stage_snapshot(tmp); ast_channel_tech_set(tmp, &skinny_tech); ast_channel_tech_pvt_set(tmp, sub); @@ -5499,6 +5502,7 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli pbx_builtin_setvar_helper(tmp, v->name, v->value); ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); if (state != AST_STATE_DOWN) { if (ast_pbx_start(tmp)) { diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c index 547cd7c2f..93fd9c502 100644 --- a/channels/chan_unistim.c +++ b/channels/chan_unistim.c @@ -2517,10 +2517,12 @@ static void *unistim_ss(void *data) int res; ast_verb(3, "Starting switch on '%s@%s-%d' to %s\n", l->name, l->parent->name, sub->softkey, s->device->phone_number); + ast_channel_lock(chan); ast_channel_exten_set(chan, s->device->phone_number); + ast_setstate(chan, AST_STATE_RING); + ast_channel_unlock(chan); ast_copy_string(s->device->redial_number, s->device->phone_number, sizeof(s->device->redial_number)); - ast_setstate(chan, AST_STATE_RING); res = ast_pbx_run(chan); if (res) { ast_log(LOG_WARNING, "PBX exited non-zero\n"); @@ -5563,6 +5565,7 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state return NULL; } + ast_channel_lock(tmp); ast_channel_stage_snapshot(tmp); ast_format_cap_copy(ast_channel_nativeformats(tmp), l->cap); @@ -5627,6 +5630,7 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state ast_channel_priority_set(tmp, 1); ast_channel_stage_snapshot_done(tmp); + ast_channel_unlock(tmp); if (state != AST_STATE_DOWN) { if (unistimdebug) { diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc index 12f27249b..6ee0e0618 100644 --- a/channels/chan_vpb.cc +++ b/channels/chan_vpb.cc @@ -2439,6 +2439,7 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state st tmp = ast_channel_alloc(1, state, 0, 0, "", me->ext, me->context, linkedid, AST_AMA_NONE, "%s", me->dev); if (tmp) { + ast_channel_lock(tmp); if (use_ast_ind == 1){ ast_channel_tech_set(tmp, &vpb_tech_indicate); } else { @@ -2471,6 +2472,7 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state st ast_channel_exten_set(tmp, "s"); if (!ast_strlen_zero(me->language)) ast_channel_language_set(tmp, me->language); + ast_channel_unlock(tmp); me->owner = tmp; diff --git a/channels/sig_analog.c b/channels/sig_analog.c index bbf7a3c8c..51d3f1495 100644 --- a/channels/sig_analog.c +++ b/channels/sig_analog.c @@ -2120,6 +2120,7 @@ static void *__analog_ss_thread(void *data) getforward = 0; } else { res = analog_play_tone(p, idx, -1); + ast_channel_lock(chan); ast_channel_exten_set(chan, exten); if (!ast_strlen_zero(p->cid_num)) { if (!p->hidecallerid) { @@ -2134,6 +2135,7 @@ static void *__analog_ss_thread(void *data) } } ast_setstate(chan, AST_STATE_RING); + ast_channel_unlock(chan); analog_set_echocanceller(p, 1); res = ast_pbx_run(chan); if (res) { @@ -2615,8 +2617,10 @@ static void *__analog_ss_thread(void *data) analog_handle_notify_message(chan, p, flags, -1); + ast_channel_lock(chan); ast_setstate(chan, AST_STATE_RING); ast_channel_rings_set(chan, 1); + ast_channel_unlock(chan); analog_set_ringtimeout(p, p->ringt_base); res = ast_pbx_run(chan); if (res) { diff --git a/channels/sig_pri.c b/channels/sig_pri.c index 5def34c23..48c8c33d7 100644 --- a/channels/sig_pri.c +++ b/channels/sig_pri.c @@ -2160,7 +2160,9 @@ static void *pri_ss_thread(void *data) #endif /* defined(ISSUE_16789) */ sig_pri_set_echocanceller(p, 1); + ast_channel_lock(chan); ast_setstate(chan, AST_STATE_RING); + ast_channel_unlock(chan); res = ast_pbx_run(chan); if (res) { ast_log(LOG_WARNING, "PBX exited non-zero!\n"); diff --git a/funcs/func_timeout.c b/funcs/func_timeout.c index 3c2810fd5..e93ce3f62 100644 --- a/funcs/func_timeout.c +++ b/funcs/func_timeout.c @@ -155,7 +155,9 @@ static int timeout_write(struct ast_channel *chan, const char *cmd, char *data, switch (*data) { case 'a': case 'A': + ast_channel_lock(chan); ast_channel_setwhentohangup_tv(chan, when); + ast_channel_unlock(chan); if (!ast_tvzero(*ast_channel_whentohangup(chan))) { when = ast_tvadd(when, ast_tvnow()); ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S.%3q %Z", diff --git a/include/asterisk/aoc.h b/include/asterisk/aoc.h index 727362c1f..171fbb300 100644 --- a/include/asterisk/aoc.h +++ b/include/asterisk/aoc.h @@ -497,7 +497,10 @@ int ast_aoc_s_add_special_arrangement(struct ast_aoc_decoded *decoded, */ int ast_aoc_decoded2str(const struct ast_aoc_decoded *decoded, struct ast_str **msg); -/*! \brief generate AOC manager event for an AOC-S, AOC-D, or AOC-E msg */ +/*! + * \brief generate AOC manager event for an AOC-S, AOC-D, or AOC-E msg + * \pre chan is locked + */ int ast_aoc_manager_event(const struct ast_aoc_decoded *decoded, struct ast_channel *chan); /*! \brief get the message type, AOC-D, AOC-E, or AOC Request */ diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 7db2b3c3a..29d551b12 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -1535,8 +1535,7 @@ int ast_channel_cmpwhentohangup_tv(struct ast_channel *chan, struct timeval offs * \details * This function sets the absolute time out on a channel (when to hang up). * - * \note This function does not require that the channel is locked before - * calling it. + * \pre chan is locked * * \return Nothing * \sa ast_channel_setwhentohangup_tv() @@ -1552,8 +1551,7 @@ void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset) __attr * * This function sets the absolute time out on a channel (when to hang up). * - * \note This function does not require that the channel is locked before - * calling it. + * \pre chan is locked * * \return Nothing * \since 1.6.1 @@ -2337,6 +2335,8 @@ void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_ * \param chan the channel * \param vars a linked list of variables * + * \pre chan is locked + * * \details * Variable names can be for a regular channel variable or a dialplan function * that has the ability to be written to. @@ -3803,6 +3803,15 @@ void ast_channel_name_set(struct ast_channel *chan, const char *name); void ast_channel_##field##_build_va(struct ast_channel *chan, const char *fmt, va_list ap) __attribute__((format(printf, 2, 0))); \ void ast_channel_##field##_build(struct ast_channel *chan, const char *fmt, ...) __attribute__((format(printf, 2, 3))) +/*! + * The following string fields result in channel snapshot creation and + * should have the channel locked when called: + * + * \li language + * \li accountcode + * \li peeracccount + * \li linkedid + */ DECLARE_STRINGFIELD_SETTERS_FOR(name); DECLARE_STRINGFIELD_SETTERS_FOR(language); DECLARE_STRINGFIELD_SETTERS_FOR(musicclass); @@ -3854,6 +3863,10 @@ void ast_channel_sending_dtmf_digit_set(struct ast_channel *chan, char value); struct timeval ast_channel_sending_dtmf_tv(const struct ast_channel *chan); void ast_channel_sending_dtmf_tv_set(struct ast_channel *chan, struct timeval value); enum ama_flags ast_channel_amaflags(const struct ast_channel *chan); + +/*! + * \pre chan is locked + */ void ast_channel_amaflags_set(struct ast_channel *chan, enum ama_flags value); int ast_channel_epfd(const struct ast_channel *chan); void ast_channel_epfd_set(struct ast_channel *chan, int value); @@ -3937,6 +3950,10 @@ enum ast_channel_adsicpe ast_channel_adsicpe(const struct ast_channel *chan); void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value); enum ast_channel_state ast_channel_state(const struct ast_channel *chan); struct ast_callid *ast_channel_callid(const struct ast_channel *chan); + +/*! + * \pre chan is locked + */ void ast_channel_callid_set(struct ast_channel *chan, struct ast_callid *value); /* XXX Internal use only, make sure to move later */ @@ -3977,6 +3994,10 @@ void ast_channel_connected_set(struct ast_channel *chan, struct ast_party_connec void ast_channel_dialed_set(struct ast_channel *chan, struct ast_party_dialed *value); void ast_channel_redirecting_set(struct ast_channel *chan, struct ast_party_redirecting *value); void ast_channel_dtmf_tv_set(struct ast_channel *chan, struct timeval *value); + +/*! + * \pre chan is locked + */ void ast_channel_whentohangup_set(struct ast_channel *chan, struct timeval *value); void ast_channel_varshead_set(struct ast_channel *chan, struct varshead *value); struct timeval ast_channel_creationtime(struct ast_channel *chan); @@ -3992,8 +4013,14 @@ struct ast_readq_list *ast_channel_readq(struct ast_channel *chan); /* Typedef accessors */ ast_group_t ast_channel_callgroup(const struct ast_channel *chan); +/*! + * \pre chan is locked + */ void ast_channel_callgroup_set(struct ast_channel *chan, ast_group_t value); ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan); +/*! + * \pre chan is locked + */ void ast_channel_pickupgroup_set(struct ast_channel *chan, ast_group_t value); struct ast_namedgroups *ast_channel_named_callgroups(const struct ast_channel *chan); void ast_channel_named_callgroups_set(struct ast_channel *chan, struct ast_namedgroups *value); @@ -4040,6 +4067,9 @@ ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan); void ast_channel_timingfunc_set(struct ast_channel *chan, ast_timing_func_t value); struct ast_bridge *ast_channel_internal_bridge(const struct ast_channel *chan); +/*! + * \pre chan is locked + */ void ast_channel_internal_bridge_set(struct ast_channel *chan, struct ast_bridge *value); struct ast_bridge_channel *ast_channel_internal_bridge_channel(const struct ast_channel *chan); diff --git a/include/asterisk/channelstate.h b/include/asterisk/channelstate.h index f5f7392dd..08f908256 100644 --- a/include/asterisk/channelstate.h +++ b/include/asterisk/channelstate.h @@ -47,7 +47,10 @@ enum ast_channel_state { AST_STATE_MUTE = (1 << 16), /*!< Do not transmit voice data */ }; -/*! \brief Change the state of a channel */ +/*! + * \brief Change the state of a channel + * \pre chan is locked + */ int ast_setstate(struct ast_channel *chan, enum ast_channel_state); #endif /* __AST_CHANNELSTATE_H__ */ diff --git a/include/asterisk/stasis_bridges.h b/include/asterisk/stasis_bridges.h index 9412bf0b7..78b97d188 100644 --- a/include/asterisk/stasis_bridges.h +++ b/include/asterisk/stasis_bridges.h @@ -199,6 +199,9 @@ struct stasis_message_type *ast_channel_left_bridge_type(void); * should also be treated as immutable and not modified after it is put into the * message. * + * \pre bridge is locked. + * \pre No channels are locked. + * * \param bridge Channel blob is associated with, or NULL for global/all bridges. * \param blob JSON object representing the data. * \return \ref ast_bridge_blob message. @@ -213,6 +216,9 @@ struct stasis_message *ast_bridge_blob_create(struct stasis_message_type *type, * \since 12 * \brief Publish a bridge channel enter event * + * \pre bridge is locked. + * \pre No channels are locked. + * * \param bridge The bridge a channel entered * \param chan The channel that entered the bridge * \param swap The channel being swapped out of the bridge @@ -224,6 +230,9 @@ void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *cha * \since 12 * \brief Publish a bridge channel leave event * + * \pre bridge is locked. + * \pre No channels are locked. + * * \param bridge The bridge a channel left * \param chan The channel that left the bridge */ @@ -268,6 +277,8 @@ struct stasis_message_type *ast_blind_transfer_type(void); /*! * \brief Publish a blind transfer event * + * \pre No channels or bridges are locked + * * \param is_external Whether the blind transfer was initiated externally (e.g. via AMI or native protocol) * \param result The success or failure of the transfer * \param to_transferee The bridge between the transferer and transferee plus the transferer channel @@ -331,6 +342,8 @@ struct stasis_message_type *ast_attended_transfer_type(void); * Publish an \ref ast_attended_transfer_message with the dest_type set to * \c AST_ATTENDED_TRANSFER_DEST_FAIL. * + * \pre No channels or bridges are locked + * * \param is_external Indicates if the transfer was initiated externally * \param result The result of the transfer. Will always be a type of failure. * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge @@ -352,6 +365,8 @@ void ast_bridge_publish_attended_transfer_fail(int is_external, enum ast_transfe * * In either case, two bridges enter, one leaves. * + * \pre No channels or bridges are locked + * * \param is_external Indicates if the transfer was initiated externally * \param result The result of the transfer. * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge @@ -371,6 +386,8 @@ void ast_bridge_publish_attended_transfer_bridge_merge(int is_external, enum ast * this results from merging two bridges together. The difference is that a * transferer channel survives the bridge merge * + * \pre No channels or bridges are locked + * * \param is_external Indicates if the transfer was initiated externally * \param result The result of the transfer. * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge @@ -392,6 +409,8 @@ void ast_bridge_publish_attended_transfer_threeway(int is_external, enum ast_tra * \li A transferee channel leaving a bridge to run an app * \li A bridge of transferees running an app (via a local channel) * + * \pre No channels or bridges are locked + * * \param is_external Indicates if the transfer was initiated externally * \param result The result of the transfer. * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge @@ -415,6 +434,8 @@ void ast_bridge_publish_attended_transfer_app(int is_external, enum ast_transfer * When this type of transfer occurs, the two bridges continue to exist after the * transfer and a local channel is used to link the two bridges together. * + * \pre No channels or bridges are locked + * * \param is_external Indicates if the transfer was initiated externally * \param result The result of the transfer. * \param transferee The bridge between the transferer and transferees as well as the transferer channel from that bridge diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h index 519a4b676..65ea660f6 100644 --- a/include/asterisk/stasis_channels.h +++ b/include/asterisk/stasis_channels.h @@ -153,6 +153,8 @@ struct stasis_message_type *ast_channel_snapshot_type(void); * \brief Generate a snapshot of the channel state. This is an ao2 object, so * ao2_cleanup() to deallocate. * + * \pre chan is locked + * * \param chan The channel from which to generate a snapshot * * \retval pointer on success (must be unreffed) @@ -192,6 +194,8 @@ struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char * The given \a blob should be treated as immutable and not modified after it is * put into the message. * + * \pre chan is locked + * * \param chan Channel blob is associated with, or \c NULL for global/all channels. * \param type Message type for this blob. * \param blob JSON object representing the data, or \c NULL for no data. If @@ -305,6 +309,8 @@ void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, * \brief Publish a channel blob message. * \since 12.0.0 * + * \pre chan is locked + * * \param chan Channel publishing the blob. * \param type Type of stasis message. * \param blob The blob being published. (NULL if no blob) @@ -318,6 +324,8 @@ void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_ty * \since 12 * \brief Set flag to indicate channel snapshot is being staged. * + * \pre chan is locked + * * \param chan Channel being staged. */ void ast_channel_stage_snapshot(struct ast_channel *chan); @@ -326,6 +334,8 @@ void ast_channel_stage_snapshot(struct ast_channel *chan); * \since 12 * \brief Clear flag to indicate channel snapshot is being staged, and publish snapshot. * + * \pre chan is locked + * * \param chan Channel being staged. */ void ast_channel_stage_snapshot_done(struct ast_channel *chan); @@ -334,6 +344,8 @@ void ast_channel_stage_snapshot_done(struct ast_channel *chan); * \since 12 * \brief Publish a \ref ast_channel_snapshot for a channel. * + * \pre chan is locked + * * \param chan Channel to publish. */ void ast_channel_publish_snapshot(struct ast_channel *chan); @@ -342,6 +354,8 @@ void ast_channel_publish_snapshot(struct ast_channel *chan); * \since 12 * \brief Publish a \ref ast_channel_varset for a channel. * + * \pre chan is locked + * * \param chan Channel to publish the event for, or \c NULL for 'none'. * \param variable Name of the variable being set * \param value Value. @@ -533,6 +547,8 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, * \brief Publish in the \ref ast_channel_topic a \ref ast_channel_snapshot * message indicating a change in channel state * + * \pre chan is locked + * * \param chan The channel whose state has changed */ void ast_publish_channel_state(struct ast_channel *chan); diff --git a/main/bridge.c b/main/bridge.c index 1c3bf16e3..5d6d0632a 100644 --- a/main/bridge.c +++ b/main/bridge.c @@ -2497,7 +2497,13 @@ static int try_swap_optimize_out(struct ast_bridge *chan_bridge, other = ast_bridge_channel_peer(src_bridge_channel); if (other && other->state == BRIDGE_CHANNEL_STATE_WAIT) { - unsigned int id = ast_atomic_fetchadd_int((int *) &optimization_id, +1); + unsigned int id; + + if (ast_channel_trylock(other->chan)) { + return 1; + } + + id = ast_atomic_fetchadd_int((int *) &optimization_id, +1); ast_verb(3, "Move-swap optimizing %s <-- %s.\n", ast_channel_name(dst_bridge_channel->chan), @@ -2519,6 +2525,7 @@ static int try_swap_optimize_out(struct ast_bridge *chan_bridge, if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) { pvt->callbacks->optimization_finished(pvt, res == 1, id); } + ast_channel_unlock(other); } return res; } diff --git a/main/bridge_channel.c b/main/bridge_channel.c index 96bfb209a..ae33cd056 100644 --- a/main/bridge_channel.c +++ b/main/bridge_channel.c @@ -235,12 +235,16 @@ void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_chann return; } + ast_channel_lock(bridge_channel->chan); ast_channel_linkedid_set(bridge_channel->chan, oldest_linkedid); + ast_channel_unlock(bridge_channel->chan); AST_LIST_TRAVERSE(&bridge->channels, other, entry) { if (other == swap) { continue; } + ast_channel_lock(other->chan); ast_channel_linkedid_set(other->chan, oldest_linkedid); + ast_channel_unlock(other->chan); } } @@ -253,6 +257,7 @@ void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_ch if (other == swap) { continue; } + ast_channel_lock_both(bridge_channel->chan, other->chan); if (!ast_strlen_zero(ast_channel_accountcode(bridge_channel->chan)) && ast_strlen_zero(ast_channel_peeraccount(other->chan))) { ast_debug(1, "Setting peeraccount to %s for %s from data on channel %s\n", @@ -286,6 +291,8 @@ void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_ch ast_channel_peeraccount_set(bridge_channel->chan, ast_channel_accountcode(other->chan)); } } + ast_channel_unlock(bridge_channel->chan); + ast_channel_unlock(other->chan); } } @@ -624,14 +631,18 @@ int ast_bridge_channel_write_hold(struct ast_bridge_channel *bridge_channel, con datalen = 0; } + ast_channel_lock(bridge_channel->chan); ast_channel_publish_blob(bridge_channel->chan, ast_channel_hold_type(), blob); + ast_channel_unlock(bridge_channel->chan); return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD, moh_class, datalen); } int ast_bridge_channel_write_unhold(struct ast_bridge_channel *bridge_channel) { + ast_channel_lock(bridge_channel->chan); ast_channel_publish_blob(bridge_channel->chan, ast_channel_unhold_type(), NULL); + ast_channel_unlock(bridge_channel->chan); return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_UNHOLD, NULL, 0); } diff --git a/main/cel.c b/main/cel.c index db51361e9..b9f992f6f 100644 --- a/main/cel.c +++ b/main/cel.c @@ -1614,7 +1614,9 @@ void ast_cel_publish_event(struct ast_channel *chan, "event_type", event_type, "event_details", blob); + ast_channel_lock(chan); message = ast_channel_blob_create(chan, cel_generic_type(), cel_blob); + ast_channel_unlock(chan); if (message) { stasis_publish(ast_cel_topic(), message); } diff --git a/main/channel.c b/main/channel.c index 58b50c820..f1bbbda27 100644 --- a/main/channel.c +++ b/main/channel.c @@ -678,7 +678,9 @@ int ast_str2cause(const char *name) static struct stasis_message *create_channel_snapshot_message(struct ast_channel *channel) { RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup); + ast_channel_lock(channel); snapshot = ast_channel_snapshot_create(channel); + ast_channel_unlock(channel); if (!snapshot) { return NULL; } @@ -1261,6 +1263,7 @@ int ast_queue_hold(struct ast_channel *chan, const char *musicclass) struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HOLD }; int res; + ast_channel_lock(chan); if (!ast_strlen_zero(musicclass)) { f.data.ptr = (void *) musicclass; f.datalen = strlen(musicclass) + 1; @@ -1272,6 +1275,7 @@ int ast_queue_hold(struct ast_channel *chan, const char *musicclass) ast_channel_publish_blob(chan, ast_channel_hold_type(), blob); res = ast_queue_frame(chan, &f); + ast_channel_unlock(chan); return res; } @@ -1280,9 +1284,11 @@ int ast_queue_unhold(struct ast_channel *chan) struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_UNHOLD }; int res; + ast_channel_lock(chan); ast_channel_publish_blob(chan, ast_channel_unhold_type(), NULL); res = ast_queue_frame(chan, &f); + ast_channel_unlock(chan); return res; } @@ -2248,7 +2254,9 @@ static void ast_channel_destructor(void *obj) /* Things that may possibly raise Stasis messages shouldn't occur after this point */ ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEAD); + ast_channel_lock(chan); ast_channel_publish_snapshot(chan); + ast_channel_unlock(chan); publish_cache_clear(chan); ast_channel_lock(chan); @@ -5318,7 +5326,9 @@ static int set_format(struct ast_channel *chan, generator_write_format_change(chan); } + ast_channel_lock(chan); ast_channel_publish_snapshot(chan); + ast_channel_unlock(chan); return 0; } @@ -5399,7 +5409,9 @@ static int set_format(struct ast_channel *chan, generator_write_format_change(chan); } + ast_channel_lock(chan); ast_channel_publish_snapshot(chan); + ast_channel_unlock(chan); return res; } @@ -5616,7 +5628,9 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan /* Copy/inherit important information into new channel */ if (oh) { if (oh->vars) { + ast_channel_lock(new_chan); ast_set_variables(new_chan, oh->vars); + ast_channel_unlock(new_chan); } if (oh->parent_channel) { call_forward_inherit(new_chan, oh->parent_channel, orig); @@ -5677,7 +5691,9 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c if (oh) { if (oh->vars) { + ast_channel_lock(chan); ast_set_variables(chan, oh->vars); + ast_channel_unlock(chan); } if (!ast_strlen_zero(oh->cid_num) && !ast_strlen_zero(oh->cid_name)) { /* @@ -5949,7 +5965,9 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request if (requestor) { struct ast_callid *callid = ast_channel_callid(requestor); if (callid) { + ast_channel_lock(c); ast_channel_callid_set(c, callid); + ast_channel_unlock(c); callid = ast_callid_unref(callid); } } diff --git a/main/core_local.c b/main/core_local.c index 4a047032c..4b1253219 100644 --- a/main/core_local.c +++ b/main/core_local.c @@ -498,29 +498,32 @@ static void publish_local_bridge_message(struct local_pvt *p) RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup); - SCOPED_AO2LOCK(lock, p); + struct ast_channel *owner; + struct ast_channel *chan; + + ast_unreal_lock_all(&p->base, &chan, &owner); blob = ast_json_pack("{s: s, s: s, s: b}", "context", p->context, "exten", p->exten, "can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION)); if (!blob) { - return; + goto end; } multi_blob = ast_multi_channel_blob_create(blob); if (!multi_blob) { - return; + goto end; } - one_snapshot = ast_channel_snapshot_create(p->base.owner); + one_snapshot = ast_channel_snapshot_create(owner); if (!one_snapshot) { - return; + goto end; } - two_snapshot = ast_channel_snapshot_create(p->base.chan); + two_snapshot = ast_channel_snapshot_create(chan); if (!two_snapshot) { - return; + goto end; } ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot); @@ -528,10 +531,15 @@ static void publish_local_bridge_message(struct local_pvt *p) msg = stasis_message_create(ast_local_bridge_type(), multi_blob); if (!msg) { - return; + goto end; } - stasis_publish(ast_channel_topic(p->base.owner), msg); + stasis_publish(ast_channel_topic(owner), msg); + +end: + ast_channel_unlock(owner); + ast_channel_unlock(chan); + ao2_unlock(p); } int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features) diff --git a/main/core_unreal.c b/main/core_unreal.c index 7e457f484..0a4859703 100644 --- a/main/core_unreal.c +++ b/main/core_unreal.c @@ -918,8 +918,12 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p, } if (callid) { + ast_channel_lock(owner); ast_channel_callid_set(owner, callid); + ast_channel_unlock(owner); + ast_channel_lock(chan); ast_channel_callid_set(chan, callid); + ast_channel_unlock(chan); } ast_channel_tech_set(owner, tech); diff --git a/main/dial.c b/main/dial.c index 8cc6f9c89..1729af41a 100644 --- a/main/dial.c +++ b/main/dial.c @@ -286,6 +286,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe cap_request = NULL; cap_all_audio = ast_format_cap_destroy(cap_all_audio); + ast_channel_lock(channel->owner); ast_channel_stage_snapshot(channel->owner); ast_channel_appl_set(channel->owner, "AppDial2"); @@ -315,6 +316,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe } ast_channel_stage_snapshot_done(channel->owner); + ast_channel_unlock(channel->owner); return 0; } diff --git a/main/endpoints.c b/main/endpoints.c index 9eeadfeef..3480a3055 100644 --- a/main/endpoints.c +++ b/main/endpoints.c @@ -203,7 +203,9 @@ int ast_endpoint_add_channel(struct ast_endpoint *endpoint, ast_str_container_add(endpoint->channel_ids, ast_channel_uniqueid(chan)); ao2_unlock(endpoint); + ast_channel_lock(chan); ast_publish_channel_state(chan); + ast_channel_unlock(chan); endpoint_publish_snapshot(endpoint); return 0; diff --git a/main/pbx.c b/main/pbx.c index 99c686371..03b1c4a8e 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -1601,9 +1601,11 @@ int pbx_exec(struct ast_channel *c, /*!< Channel */ saved_c_appl= ast_channel_appl(c); saved_c_data= ast_channel_data(c); + ast_channel_lock(c); ast_channel_appl_set(c, app->name); ast_channel_data_set(c, data); ast_channel_publish_snapshot(c); + ast_channel_unlock(c); if (app->module) u = __ast_module_user_add(app->module, c); @@ -6101,7 +6103,9 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, if (!callid) { callid = ast_create_callid(); if (callid) { + ast_channel_lock(c); ast_channel_callid_set(c, callid); + ast_channel_unlock(c); } } ast_callid_threadassoc_add(callid); @@ -10069,6 +10073,7 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, co return -1; } + ast_channel_lock(dialed); if (vars) { ast_set_variables(dialed, vars); } @@ -10077,6 +10082,7 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, co ast_channel_accountcode_set(dialed, account); } ast_set_flag(ast_channel_flags(dialed), AST_FLAG_ORIGINATED); + ast_channel_unlock(dialed); if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) { struct ast_party_connected_line connected; @@ -10172,6 +10178,7 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, co if (failed) { char failed_reason[4] = ""; + ast_channel_lock(failed); if (!ast_strlen_zero(context)) { ast_channel_context_set(failed, context); } @@ -10184,6 +10191,7 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, co ast_set_variables(failed, vars); snprintf(failed_reason, sizeof(failed_reason), "%d", ast_dial_reason(outgoing->dial, 0)); pbx_builtin_setvar_helper(failed, "REASON", failed_reason); + ast_channel_unlock(failed); if (ast_pbx_run(failed)) { ast_log(LOG_ERROR, "Unable to run PBX on '%s'\n", ast_channel_name(failed)); @@ -10484,10 +10492,12 @@ static int pbx_builtin_busy(struct ast_channel *chan, const char *data) ast_indicate(chan, AST_CONTROL_BUSY); /* Don't change state of an UP channel, just indicate busy in audio */ + ast_channel_lock(chan); if (ast_channel_state(chan) != AST_STATE_UP) { ast_channel_hangupcause_set(chan, AST_CAUSE_BUSY); ast_setstate(chan, AST_STATE_BUSY); } + ast_channel_unlock(chan); wait_for_hangup(chan, data); return -1; } @@ -10500,10 +10510,12 @@ static int pbx_builtin_congestion(struct ast_channel *chan, const char *data) ast_indicate(chan, AST_CONTROL_CONGESTION); /* Don't change state of an UP channel, just indicate congestion in audio */ + ast_channel_lock(chan); if (ast_channel_state(chan) != AST_STATE_UP) { ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION); ast_setstate(chan, AST_STATE_BUSY); } + ast_channel_unlock(chan); wait_for_hangup(chan, data); return -1; } diff --git a/main/pickup.c b/main/pickup.c index 7ae6927fa..a415f1672 100644 --- a/main/pickup.c +++ b/main/pickup.c @@ -354,11 +354,17 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target) /* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */ ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE); - if (!(chan_snapshot = ast_channel_snapshot_create(chan))) { + ast_channel_lock(chan); + chan_snapshot = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); + if (!chan_snapshot) { goto pickup_failed; } - if (!(target_snapshot = ast_channel_snapshot_create(target))) { + ast_channel_lock(target); + target_snapshot = ast_channel_snapshot_create(target); + ast_channel_unlock(target); + if (!target_snapshot) { goto pickup_failed; } diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c index b92d048bc..dd22710b1 100644 --- a/main/stasis_bridges.c +++ b/main/stasis_bridges.c @@ -397,7 +397,9 @@ struct stasis_message *ast_bridge_blob_create( } if (chan) { + ast_channel_lock(chan); obj->channel = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); if (obj->channel == NULL) { return NULL; } @@ -579,7 +581,9 @@ static int bridge_channel_snapshot_pair_init(struct ast_bridge_channel_pair *pai } } + ast_channel_lock(pair->channel); snapshot_pair->channel_snapshot = ast_channel_snapshot_create(pair->channel); + ast_channel_unlock(pair->channel); if (!snapshot_pair->channel_snapshot) { return -1; } @@ -915,7 +919,9 @@ void ast_bridge_publish_attended_transfer_link(int is_external, enum ast_transfe transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK; for (i = 0; i < 2; ++i) { + ast_channel_lock(locals[i]); transfer_msg->dest.links[i] = ast_channel_snapshot_create(locals[i]); + ast_channel_unlock(locals[i]); if (!transfer_msg->dest.links[i]) { return; } diff --git a/main/stasis_channels.c b/main/stasis_channels.c index 38aac982e..127106ad9 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -310,14 +310,18 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_cha } if (caller) { + ast_channel_lock(caller); caller_snapshot = ast_channel_snapshot_create(caller); + ast_channel_unlock(caller); if (!caller_snapshot) { return; } ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot); } + ast_channel_lock(peer); peer_snapshot = ast_channel_snapshot_create(peer); + ast_channel_unlock(peer); if (!peer_snapshot) { return; } diff --git a/pbx/pbx_realtime.c b/pbx/pbx_realtime.c index f9f9cb2be..7624d5979 100644 --- a/pbx/pbx_realtime.c +++ b/pbx/pbx_realtime.c @@ -357,7 +357,9 @@ static int realtime_exec(struct ast_channel *chan, const char *context, const ch term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)), term_color(tmp2, ast_channel_name(chan), COLOR_BRMAGENTA, 0, sizeof(tmp2)), term_color(tmp3, S_OR(appdata, ""), COLOR_BRMAGENTA, 0, sizeof(tmp3))); + ast_channel_lock(chan); snapshot = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); if (snapshot) { /* pbx_exec sets application name and data, but we don't want to log * every exec. Just update the snapshot here instead. diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index 4f39e2e94..a939fdac7 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -530,6 +530,7 @@ static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, /* Set parking timeout channel variables */ snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space); + ast_channel_lock(chan); ast_channel_stage_snapshot(chan); pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space); pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */ @@ -538,6 +539,7 @@ static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat); parking_timeout_set_caller_features(chan, user->lot->cfg); ast_channel_stage_snapshot_done(chan); + ast_channel_unlock(chan); /* Dialplan generation for park-dial extensions */ diff --git a/res/parking/parking_manager.c b/res/parking/parking_manager.c index 0c577018a..507273aec 100644 --- a/res/parking/parking_manager.c +++ b/res/parking/parking_manager.c @@ -155,7 +155,9 @@ static struct ast_parked_call_payload *parked_call_payload_from_failure(struct a RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup); RAII_VAR(struct ast_channel_snapshot *, parkee_snapshot, NULL, ao2_cleanup); + ast_channel_lock(chan); parkee_snapshot = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); if (!parkee_snapshot) { return NULL; } @@ -172,7 +174,9 @@ static struct ast_parked_call_payload *parked_call_payload_from_parked_user(stru struct timeval now = ast_tvnow(); const char *lot_name = pu->lot->name; + ast_channel_lock(pu->chan); parkee_snapshot = ast_channel_snapshot_create(pu->chan); + ast_channel_unlock(pu->chan); if (!parkee_snapshot) { return NULL; diff --git a/res/res_agi.c b/res/res_agi.c index ed70356dd..96d3906ac 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -1481,9 +1481,11 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char to execute based on the setup info */ ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, ast_uri_http); startblob = ast_json_pack("{s: s}", "Env", ami_buffer); + ast_channel_lock(chan); ast_channel_publish_blob(chan, agi_async_start_type(), startblob); hungup = ast_check_hangup(chan); + ast_channel_unlock(chan); for (;;) { /* * Process as many commands as we can. Commands are added via @@ -1527,7 +1529,9 @@ static enum agi_result launch_asyncagi(struct ast_channel *chan, int argc, char if (execblob && !ast_strlen_zero(cmd->cmd_id)) { ast_json_object_set(execblob, "CommandId", ast_json_string_create(cmd->cmd_id)); } + ast_channel_lock(chan); ast_channel_publish_blob(chan, agi_async_exec_type(), execblob); + ast_channel_unlock(chan); free_agi_cmd(cmd); @@ -1587,7 +1591,9 @@ async_agi_done: ast_speech_destroy(async_agi.speech); } /* notify manager users this channel cannot be controlled anymore by Async AGI */ + ast_channel_lock(chan); ast_channel_publish_blob(chan, agi_async_end_type(), NULL); + ast_channel_unlock(chan); async_agi_abort: /* close the pipe */ @@ -2716,7 +2722,9 @@ static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const whentohangup.tv_sec = timeout; whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0; } + ast_channel_lock(chan); ast_channel_setwhentohangup_tv(chan, whentohangup); + ast_channel_unlock(chan); ast_agi_send(agi->fd, chan, "200 result=0\n"); return RESULT_SUCCESS; } @@ -3657,7 +3665,9 @@ static void publish_async_exec_end(struct ast_channel *chan, int command_id, con "Command", command, "ResultCode", result_code, "Result", result); + ast_channel_lock(chan); ast_channel_publish_blob(chan, agi_exec_end_type(), blob); + ast_channel_unlock(chan); } static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead) @@ -3675,7 +3685,9 @@ static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, ch startblob = ast_json_pack("{s: i, s: s}", "CommandId", command_id, "Command", ami_cmd); + ast_channel_lock(chan); ast_channel_publish_blob(chan, agi_exec_start_type(), startblob); + ast_channel_unlock(chan); parse_args(buf, &argc, argv); c = find_command(argv, 0); diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c index 91da22fde..da48e523b 100644 --- a/res/res_pjsip_refer.c +++ b/res/res_pjsip_refer.c @@ -754,7 +754,9 @@ static int refer_incoming_invite_request(struct ast_sip_session *session, struct goto end; } + ast_channel_lock(session->channel); ast_setstate(session->channel, AST_STATE_RING); + ast_channel_unlock(session->channel); ast_raw_answer(session->channel); if (!invite.bridge) { diff --git a/res/res_stasis.c b/res/res_stasis.c index 691462722..5684d3dd8 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -637,7 +637,9 @@ static int send_start_msg(struct stasis_app *app, struct ast_channel *chan, ast_assert(chan != NULL); /* Set channel info */ + ast_channel_lock(chan); snapshot = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); if (!snapshot) { return -1; } @@ -681,7 +683,9 @@ static int send_end_msg(struct stasis_app *app, struct ast_channel *chan) ast_assert(chan != NULL); /* Set channel info */ + ast_channel_lock(chan); snapshot = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); if (snapshot == NULL) { return -1; } diff --git a/tests/test_cdr.c b/tests/test_cdr.c index 57d5b2e32..efbda86c4 100644 --- a/tests/test_cdr.c +++ b/tests/test_cdr.c @@ -272,9 +272,11 @@ static void clear_mock_cdr_backend(void) if ((priority) > 0) { \ ast_channel_priority_set((channel), (priority)); \ } \ + ast_channel_lock((channel)); \ ast_channel_appl_set((channel), (application)); \ ast_channel_data_set((channel), (data)); \ ast_channel_publish_snapshot((channel)); \ + ast_channel_unlock((channel)); \ } while (0) /*! \brief Hang up a test channel safely */ @@ -630,9 +632,11 @@ AST_TEST_DEFINE(test_cdr_single_party) SWAP_CONFIG(config, debug_cdr_config); CREATE_ALICE_CHANNEL(chan, &caller, &expected); + ast_channel_lock(chan); EMULATE_APP_DATA(chan, 1, "Answer", ""); ast_setstate(chan, AST_STATE_UP); EMULATE_APP_DATA(chan, 2, "VoiceMailMain", "1"); + ast_channel_unlock(chan); HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL); @@ -679,9 +683,11 @@ AST_TEST_DEFINE(test_cdr_single_bridge) SWAP_CONFIG(config, debug_cdr_config); CREATE_ALICE_CHANNEL(chan, &caller, &expected); + ast_channel_lock(chan); EMULATE_APP_DATA(chan, 1, "Answer", ""); ast_setstate(chan, AST_STATE_UP); EMULATE_APP_DATA(chan, 2, "Bridge", ""); + ast_channel_unlock(chan); bridge = ast_bridge_basic_new(); ast_test_validate(test, bridge != NULL); @@ -754,9 +760,11 @@ AST_TEST_DEFINE(test_cdr_single_bridge_continue) CREATE_ALICE_CHANNEL(chan, &caller, &expected_one); COPY_IDS(chan, &expected_two); + ast_channel_lock(chan); EMULATE_APP_DATA(chan, 1, "Answer", ""); ast_setstate(chan, AST_STATE_UP); EMULATE_APP_DATA(chan, 2, "Bridge", ""); + ast_channel_unlock(chan); bridge_one = ast_bridge_basic_new(); ast_test_validate(test, bridge_one != NULL); @@ -838,9 +846,11 @@ AST_TEST_DEFINE(test_cdr_single_twoparty_bridge_a) CREATE_BOB_CHANNEL(chan_bob, &caller_bob, &bob_expected); ast_copy_string(bob_expected.linkedid, ast_channel_linkedid(chan_alice), sizeof(bob_expected.linkedid)); + ast_channel_lock(chan_alice); EMULATE_APP_DATA(chan_alice, 1, "Answer", ""); ast_setstate(chan_alice, AST_STATE_UP); EMULATE_APP_DATA(chan_alice, 2, "Bridge", ""); + ast_channel_unlock(chan_alice); bridge = ast_bridge_basic_new(); ast_test_validate(test, bridge != NULL); @@ -848,9 +858,11 @@ AST_TEST_DEFINE(test_cdr_single_twoparty_bridge_a) ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)); while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)); + ast_channel_lock(chan_bob); EMULATE_APP_DATA(chan_bob, 1, "Answer", ""); ast_setstate(chan_bob, AST_STATE_UP); EMULATE_APP_DATA(chan_bob, 2, "Bridge", ""); + ast_channel_unlock(chan_bob); ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)); while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)); @@ -926,16 +938,20 @@ AST_TEST_DEFINE(test_cdr_single_twoparty_bridge_b) CREATE_BOB_CHANNEL(chan_bob, &caller_bob, &bob_expected); ast_copy_string(bob_expected.linkedid, ast_channel_linkedid(chan_alice), sizeof(bob_expected.linkedid)); + ast_channel_unlock(chan_alice); EMULATE_APP_DATA(chan_alice, 1, "Answer", ""); ast_setstate(chan_alice, AST_STATE_UP); EMULATE_APP_DATA(chan_alice, 2, "Bridge", ""); + ast_channel_unlock(chan_alice); bridge = ast_bridge_basic_new(); ast_test_validate(test, bridge != NULL); + ast_channel_lock(chan_bob); EMULATE_APP_DATA(chan_bob, 1, "Answer", ""); ast_setstate(chan_bob, AST_STATE_UP); EMULATE_APP_DATA(chan_bob, 2, "Bridge", ""); + ast_channel_unlock(chan_bob); while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)); ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)); @@ -1049,9 +1065,11 @@ AST_TEST_DEFINE(test_cdr_single_multiparty_bridge) CREATE_CHARLIE_CHANNEL(chan_charlie, &caller_charlie, &charlie_expected); ast_copy_string(charlie_expected.linkedid, ast_channel_linkedid(chan_alice), sizeof(charlie_expected.linkedid)); + ast_channel_lock(chan_alice); EMULATE_APP_DATA(chan_alice, 1, "Answer", ""); ast_setstate(chan_alice, AST_STATE_UP); EMULATE_APP_DATA(chan_alice, 2, "Bridge", ""); + ast_channel_unlock(chan_alice); bridge = ast_bridge_basic_new(); ast_test_validate(test, bridge != NULL); @@ -1059,18 +1077,22 @@ AST_TEST_DEFINE(test_cdr_single_multiparty_bridge) ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)); + ast_channel_lock(chan_bob); EMULATE_APP_DATA(chan_bob, 1, "Answer", ""); ast_setstate(chan_bob, AST_STATE_UP); EMULATE_APP_DATA(chan_bob, 2, "Bridge", ""); + ast_channel_unlock(chan_bob); while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)); ast_test_validate(test, !ast_bridge_impart(bridge, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)); while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)); + ast_channel_lock(chan_charlie); EMULATE_APP_DATA(chan_charlie, 1, "Answer", ""); ast_setstate(chan_charlie, AST_STATE_UP); EMULATE_APP_DATA(chan_charlie, 2, "Bridge", ""); + ast_channel_unlock(chan_charlie); ast_test_validate(test, !ast_bridge_impart(bridge, chan_charlie, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)); while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)); @@ -2000,10 +2022,15 @@ AST_TEST_DEFINE(test_cdr_park) CREATE_ALICE_CHANNEL(chan_alice, &alice_caller, &alice_expected); CREATE_BOB_CHANNEL(chan_bob, &bob_caller, &bob_expected); + ast_channel_lock(chan_alice); EMULATE_APP_DATA(chan_alice, 1, "Park", "700"); ast_setstate(chan_alice, AST_STATE_UP); + ast_channel_unlock(chan_alice); + + ast_channel_lock(chan_bob); EMULATE_APP_DATA(chan_bob, 1, "Park", "701"); ast_setstate(chan_bob, AST_STATE_UP); + ast_channel_unlock(chan_bob); bridge = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_HOLDING, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM @@ -2108,6 +2135,7 @@ AST_TEST_DEFINE(test_cdr_fields) ast_copy_string(fork_expected_two.linkedid, ast_channel_linkedid(chan), sizeof(fork_expected_two.linkedid)); /* Channel enters Wait app */ + ast_channel_lock(chan); ast_channel_appl_set(chan, "Wait"); ast_channel_data_set(chan, "10"); ast_channel_priority_set(chan, 1); @@ -2116,6 +2144,7 @@ AST_TEST_DEFINE(test_cdr_fields) /* Set properties on the channel that propagate to the CDR */ ast_channel_amaflags_set(chan, AST_AMA_OMIT); ast_channel_accountcode_set(chan, "XXX"); + ast_channel_unlock(chan); /* Wait one second so we get a duration. */ while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)); @@ -2208,6 +2237,7 @@ AST_TEST_DEFINE(test_cdr_fields) ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0); /* Channel enters Answer app */ + ast_channel_lock(chan); ast_channel_appl_set(chan, "Answer"); ast_channel_data_set(chan, ""); ast_channel_priority_set(chan, 1); @@ -2216,6 +2246,7 @@ AST_TEST_DEFINE(test_cdr_fields) /* Set properties on the last record */ ast_channel_accountcode_set(chan, "ZZZ"); + ast_channel_unlock(chan); ast_cdr_setuserfield(ast_channel_name(chan), "schmackity"); ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_2") == 0); @@ -2385,7 +2416,9 @@ AST_TEST_DEFINE(test_cdr_fork_cdr) ast_test_validate(test, ast_cdr_fork(ast_channel_name(chan), &fork_options) == 0); /* Test keep variables; setting a new answer time */ + ast_channel_lock(chan); ast_setstate(chan, AST_STATE_UP); + ast_channel_unlock(chan); while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR)); ast_test_validate(test, ast_cdr_setvar(ast_channel_name(chan), "test_variable", "record_2") == 0); ast_test_validate(test, ast_cdr_getvar(ast_channel_name(chan), "test_variable", varbuffer, sizeof(varbuffer)) == 0); diff --git a/tests/test_cel.c b/tests/test_cel.c index 0aa8b601c..a90dfbf3e 100644 --- a/tests/test_cel.c +++ b/tests/test_cel.c @@ -1551,10 +1551,14 @@ AST_TEST_DEFINE(test_cel_local_optimize) CREATE_ALICE_CHANNEL(chan_alice, &alice_caller); CREATE_BOB_CHANNEL(chan_bob, &bob_caller); + ast_channel_lock(chan_alice); alice_snapshot = ast_channel_snapshot_create(chan_alice); + ast_channel_unlock(chan_alice); ast_test_validate(test, alice_snapshot != NULL); + ast_channel_lock(chan_bob); bob_snapshot = ast_channel_snapshot_create(chan_bob); + ast_channel_unlock(chan_bob); ast_test_validate(test, bob_snapshot != NULL); ast_multi_channel_blob_add_channel(mc_blob, "1", alice_snapshot); @@ -1675,7 +1679,9 @@ static int append_expected_event( const char *peer) { RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup); + ast_channel_lock(chan); snapshot = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); if (!snapshot) { return -1; } diff --git a/tests/test_stasis_channels.c b/tests/test_stasis_channels.c index 45f1e2ba3..b7c9fe2c5 100644 --- a/tests/test_stasis_channels.c +++ b/tests/test_stasis_channels.c @@ -77,10 +77,12 @@ AST_TEST_DEFINE(channel_blob_create) "foo", "bar"); /* Off nominal creation */ + ast_channel_lock(chan); ast_test_validate(test, NULL == ast_channel_blob_create(chan, NULL, json)); /* Test for single channel */ msg = ast_channel_blob_create(chan, type, json); + ast_channel_unlock(chan); ast_test_validate(test, NULL != msg); blob = stasis_message_data(msg); ast_test_validate(test, NULL != blob); @@ -129,7 +131,9 @@ AST_TEST_DEFINE(null_blob) "foo", "bar"); /* Test for single channel */ + ast_channel_lock(chan); msg = ast_channel_blob_create(chan, type, NULL); + ast_channel_unlock(chan); ast_test_validate(test, NULL != msg); blob = stasis_message_data(msg); ast_test_validate(test, NULL != blob); @@ -196,9 +200,15 @@ AST_TEST_DEFINE(multi_channel_blob_snapshots) chan_charlie = ast_channel_alloc(0, AST_STATE_DOWN, "300", "Bob", "300", "300", "default", NULL, 0, "TEST/Charlie"); blob = ast_multi_channel_blob_create(json); + ast_channel_lock(chan_alice); ast_multi_channel_blob_add_channel(blob, "Caller", ast_channel_snapshot_create(chan_alice)); + ast_channel_unlock(chan_alice); + ast_channel_lock(chan_bob); ast_multi_channel_blob_add_channel(blob, "Peer", ast_channel_snapshot_create(chan_bob)); + ast_channel_unlock(chan_bob); + ast_channel_lock(chan_charlie); ast_multi_channel_blob_add_channel(blob, "Peer", ast_channel_snapshot_create(chan_charlie)); + ast_channel_unlock(chan_charlie); /* Test for unknown role */ ast_test_validate(test, NULL == ast_multi_channel_blob_get_channel(blob, "Foobar")); @@ -252,7 +262,9 @@ AST_TEST_DEFINE(channel_snapshot_json) chan = ast_channel_alloc(0, AST_STATE_DOWN, "cid_num", "cid_name", "acctcode", "exten", "context", NULL, 0, "TEST/name"); ast_test_validate(test, NULL != chan); + ast_channel_lock(chan); snapshot = ast_channel_snapshot_create(chan); + ast_channel_unlock(chan); ast_test_validate(test, NULL != snapshot); actual = ast_channel_snapshot_to_json(snapshot, NULL); -- cgit v1.2.3