From b2ef13cb609b31702cfd34063712848d41575421 Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Tue, 15 Feb 2011 16:18:43 +0000 Subject: Merged revisions 307879 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.8 ........ r307879 | rmudgett | 2011-02-15 10:13:55 -0600 (Tue, 15 Feb 2011) | 37 lines No response sent for SIP CC subscribe/resubscribe request. Asterisk does not send a response if we try to subscribe for call completion after we have received a 180 Ringing. You can only subscribe for call completion when the call has been cleared. When we receive the 180 Ringing, for this call, its call-completion state is 'CC_AVAILABLE'. If we then send a subscribe message to Asterisk, it trys to change the call-completion state to 'CC_CALLER_REQUESTED'. Because this is an invalid state change, it just ignores the message. The only state Asterisk will accept our subscribe message is in the 'CC_CALLER_OFFERED' state. Asterisk will go into the 'CC_CALLER_OFFERED' when the SIP client clears the call by sending a CANCEL. Asterisk should always send a response. Even if its a negative one. The fix is to allow for the CCSS core to notify a CC agent that a failure has occurred when CC is requested. The "ack" callback is replaced with a "respond" callback. The "respond" callback has a parameter indicating either a successful response or a specific type of failure that may need to be communicated to the requester. (closes issue #18336) Reported by: GeorgeKonopacki Tested by: mmichelson, rmudgett JIRA SWP-2633 (closes issue #18337) Reported by: GeorgeKonopacki Tested by: mmichelson JIRA SWP-2634 ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@307883 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_dahdi.c | 2 +- channels/chan_sip.c | 26 ++++++++++++++++++----- channels/sig_pri.c | 57 ++++++++++++++++++++++++++++++++++++++++++--------- channels/sig_pri.h | 2 +- 4 files changed, 70 insertions(+), 17 deletions(-) (limited to 'channels') diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 888a8f27f..58e275350 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -16205,7 +16205,7 @@ static struct ast_cc_agent_callbacks dahdi_pri_cc_agent_callbacks = { .init = dahdi_pri_cc_agent_init, .start_offer_timer = sig_pri_cc_agent_start_offer_timer, .stop_offer_timer = sig_pri_cc_agent_stop_offer_timer, - .ack = sig_pri_cc_agent_req_ack, + .respond = sig_pri_cc_agent_req_rsp, .status_request = sig_pri_cc_agent_status_req, .stop_ringing = sig_pri_cc_agent_stop_ringing, .party_b_free = sig_pri_cc_agent_party_b_free, diff --git a/channels/chan_sip.c b/channels/chan_sip.c index ed4f0162b..06e23ad07 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1614,7 +1614,7 @@ struct ast_channel_tech sip_tech_info; static int sip_cc_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan); static int sip_cc_agent_start_offer_timer(struct ast_cc_agent *agent); static int sip_cc_agent_stop_offer_timer(struct ast_cc_agent *agent); -static void sip_cc_agent_ack(struct ast_cc_agent *agent); +static void sip_cc_agent_respond(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason); static int sip_cc_agent_status_request(struct ast_cc_agent *agent); static int sip_cc_agent_start_monitoring(struct ast_cc_agent *agent); static int sip_cc_agent_recall(struct ast_cc_agent *agent); @@ -1625,7 +1625,7 @@ static struct ast_cc_agent_callbacks sip_cc_agent_callbacks = { .init = sip_cc_agent_init, .start_offer_timer = sip_cc_agent_start_offer_timer, .stop_offer_timer = sip_cc_agent_stop_offer_timer, - .ack = sip_cc_agent_ack, + .respond = sip_cc_agent_respond, .status_request = sip_cc_agent_status_request, .start_monitoring = sip_cc_agent_start_monitoring, .callee_available = sip_cc_agent_recall, @@ -1726,14 +1726,30 @@ static int sip_cc_agent_stop_offer_timer(struct ast_cc_agent *agent) return 0; } -static void sip_cc_agent_ack(struct ast_cc_agent *agent) +static void sip_cc_agent_respond(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason) { struct sip_cc_agent_pvt *agent_pvt = agent->private_data; sip_pvt_lock(agent_pvt->subscribe_pvt); ast_set_flag(&agent_pvt->subscribe_pvt->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); - transmit_response(agent_pvt->subscribe_pvt, "200 OK", &agent_pvt->subscribe_pvt->initreq); - transmit_cc_notify(agent, agent_pvt->subscribe_pvt, CC_QUEUED); + if (reason == AST_CC_AGENT_RESPONSE_SUCCESS || !ast_strlen_zero(agent_pvt->notify_uri)) { + /* The second half of this if statement may be a bit hard to grasp, + * so here's an explanation. When a subscription comes into + * chan_sip, as long as it is not malformed, it will be passed + * to the CC core. If the core senses an out-of-order state transition, + * then the core will call this callback with the "reason" set to a + * failure condition. + * However, an out-of-order state transition will occur during a resubscription + * for CC. In such a case, we can see that we have already generated a notify_uri + * and so we can detect that this isn't a *real* failure. Rather, it is just + * something the core doesn't recognize as a legitimate SIP state transition. + * Thus we respond with happiness and flowers. + */ + transmit_response(agent_pvt->subscribe_pvt, "200 OK", &agent_pvt->subscribe_pvt->initreq); + transmit_cc_notify(agent, agent_pvt->subscribe_pvt, CC_QUEUED); + } else { + transmit_response(agent_pvt->subscribe_pvt, "500 Internal Error", &agent_pvt->subscribe_pvt->initreq); + } sip_pvt_unlock(agent_pvt->subscribe_pvt); agent_pvt->is_available = TRUE; } diff --git a/channels/sig_pri.c b/channels/sig_pri.c index 58f6c82b2..b3117f533 100644 --- a/channels/sig_pri.c +++ b/channels/sig_pri.c @@ -8542,38 +8542,75 @@ int sig_pri_cc_agent_stop_offer_timer(struct ast_cc_agent *agent) #if defined(HAVE_PRI_CCSS) /*! - * \brief Acknowledge CC request. + * \brief Response to a CC request. * \since 1.8 * * \param agent CC core agent control. + * \param reason CC request response status. * * \details * When the core receives knowledge that a called * party has accepted a CC request, it will call - * this callback. + * this callback. The core may also call this + * if there is some error when attempting to process + * the incoming CC request. * - * The duty of this is to accept a CC request from - * the caller by acknowledging receipt of that request. + * The duty of this is to issue a propper response to a + * CC request from the caller by acknowledging receipt + * of that request or rejecting it. * * \return Nothing */ -void sig_pri_cc_agent_req_ack(struct ast_cc_agent *agent) +void sig_pri_cc_agent_req_rsp(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason) { struct sig_pri_cc_agent_prv *cc_pvt; int res; + int status; + const char *failed_msg; + static const char *failed_to_send = "Failed to send the CC request response."; + static const char *not_accepted = "The core declined the CC request."; cc_pvt = agent->private_data; ast_mutex_lock(&cc_pvt->pri->lock); if (cc_pvt->cc_request_response_pending) { cc_pvt->cc_request_response_pending = 0; - res = pri_cc_req_rsp(cc_pvt->pri->pri, cc_pvt->cc_id, 0/* success */); + + /* Convert core response reason to ISDN response status. */ + status = 2;/* short_term_denial */ + switch (reason) { + case AST_CC_AGENT_RESPONSE_SUCCESS: + status = 0;/* success */ + break; + case AST_CC_AGENT_RESPONSE_FAILURE_INVALID: + status = 2;/* short_term_denial */ + break; + case AST_CC_AGENT_RESPONSE_FAILURE_TOO_MANY: + status = 5;/* queue_full */ + break; + } + + res = pri_cc_req_rsp(cc_pvt->pri->pri, cc_pvt->cc_id, status); + if (!status) { + /* CC core request was accepted. */ + if (res) { + failed_msg = failed_to_send; + } else { + failed_msg = NULL; + } + } else { + /* CC core request was declined. */ + if (res) { + failed_msg = failed_to_send; + } else { + failed_msg = not_accepted; + } + } } else { - res = 0; + failed_msg = NULL; } ast_mutex_unlock(&cc_pvt->pri->lock); - if (res) { - ast_cc_failed(agent->core_id, "%s agent failed to send the CC request ack.", - sig_pri_cc_type_name); + if (failed_msg) { + ast_cc_failed(agent->core_id, "%s agent: %s", sig_pri_cc_type_name, failed_msg); } } #endif /* defined(HAVE_PRI_CCSS) */ diff --git a/channels/sig_pri.h b/channels/sig_pri.h index ae2f97c52..14383963f 100644 --- a/channels/sig_pri.h +++ b/channels/sig_pri.h @@ -591,7 +591,7 @@ void sig_pri_sendtext(struct sig_pri_chan *pchan, const char *text); int sig_pri_cc_agent_init(struct ast_cc_agent *agent, struct sig_pri_chan *pvt_chan); int sig_pri_cc_agent_start_offer_timer(struct ast_cc_agent *agent); int sig_pri_cc_agent_stop_offer_timer(struct ast_cc_agent *agent); -void sig_pri_cc_agent_req_ack(struct ast_cc_agent *agent); +void sig_pri_cc_agent_req_rsp(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason); int sig_pri_cc_agent_status_req(struct ast_cc_agent *agent); int sig_pri_cc_agent_stop_ringing(struct ast_cc_agent *agent); int sig_pri_cc_agent_party_b_free(struct ast_cc_agent *agent); -- cgit v1.2.3