summaryrefslogtreecommitdiff
path: root/channels
diff options
context:
space:
mode:
authorChristof Lauber <christof.lauber@annax.ch>2015-11-13 14:58:15 +0100
committerJoshua Colp <jcolp@digium.com>2015-12-07 10:04:42 -0400
commit48c065e46db8c8f9301ee0220229a58c43f958ec (patch)
tree75a08e04afd8e62d04e20e071cd76020303832fa /channels
parent175950608208296a65c5f9113df677a5e542f45c (diff)
chan_sip: Support parsing of Q.850 reason header in SIP BYE and CANCEL requests.
Current support for reason header did work only in SIP responses. According to RFC3336 the reason header might appear in any SIP request. But it seems to make most sence in BYE and CANCEL so parasing is done there too (if use_q850_reason=yes). Change-Id: Ib6be7b34c23a76d0e98dfd0816c89931000ac790
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_sip.c71
1 files changed, 52 insertions, 19 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 3b200e217..4870d0f4a 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1399,6 +1399,7 @@ static char *remove_uri_parameters(char *uri);
static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req);
static int get_also_info(struct sip_pvt *p, struct sip_request *oreq);
static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req);
+static int use_reason_header(struct sip_pvt *pvt, struct sip_request *req);
static int set_address_from_contact(struct sip_pvt *pvt);
static void check_via(struct sip_pvt *p, const struct sip_request *req);
static int get_rpid(struct sip_pvt *p, struct sip_request *oreq);
@@ -16121,6 +16122,49 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req)
return TRUE;
}
+/*!
+ * \brief Parses SIP reason header according to RFC3326 and sets channel's hangupcause if configured so
+ * and header present
+ *
+ * \note This is used in BYE and CANCEL request and SIP response, but according to RFC3326 it could
+ * appear in any request, but makes not a lot of sense in others than BYE or CANCEL.
+ * Currently only implemented for Q.850 status codes.
+ * \retval 0 success
+ * \retval -1 on failure or if not configured
+ */
+static int use_reason_header(struct sip_pvt *pvt, struct sip_request *req)
+{
+ int ret, cause;
+ const char *rp, *rh;
+
+ if (!pvt->owner) {
+ return -1;
+ }
+
+ if (!ast_test_flag(&pvt->flags[1], SIP_PAGE2_Q850_REASON) ||
+ !(rh = sip_get_header(req, "Reason"))) {
+ return -1;
+ }
+
+ rh = ast_skip_blanks(rh);
+ if (strncasecmp(rh, "Q.850", 5)) {
+ return -1;
+ }
+
+ ret = -1;
+ cause = ast_channel_hangupcause(pvt->owner);
+ rp = strstr(rh, "cause=");
+ if (rp && sscanf(rp + 6, "%3d", &cause) == 1) {
+ ret = 0;
+ ast_channel_hangupcause_set(pvt->owner, cause & 0x7f);
+ if (req->debug) {
+ ast_verbose("Using Reason header for cause code: %d\n",
+ ast_channel_hangupcause(pvt->owner));
+ }
+ }
+ return ret;
+}
+
/*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled
*
* \note This calls parse_uri which has the unexpected property that passing more
@@ -24107,27 +24151,13 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
msg = "";
sipmethod = find_sip_method(msg);
-
owner = p->owner;
if (owner) {
- const char *rp = NULL, *rh = NULL;
-
ast_channel_hangupcause_set(owner, 0);
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_Q850_REASON) && (rh = sip_get_header(req, "Reason"))) {
- rh = ast_skip_blanks(rh);
- if (!strncasecmp(rh, "Q.850", 5)) {
- int cause = ast_channel_hangupcause(owner);
- rp = strstr(rh, "cause=");
- if (rp && sscanf(rp + 6, "%30d", &cause) == 1) {
- ast_channel_hangupcause_set(owner, cause & 0x7f);
- if (req->debug)
- ast_verbose("Using Reason header for cause code: %d\n", ast_channel_hangupcause(owner));
- }
- }
- }
-
- if (!ast_channel_hangupcause(owner))
+ if (use_reason_header(p, req)) {
+ /* Use the SIP cause */
ast_channel_hangupcause_set(owner, hangup_sip2cause(resp));
+ }
}
if (p->socket.type == AST_TRANSPORT_UDP) {
@@ -26419,6 +26449,8 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req)
return 0;
}
+ use_reason_header(p, req);
+
/* At this point, we could have cancelled the invite at the same time
as the other side sends a CANCEL. Our final reply with error code
might not have been received by the other side before the CANCEL
@@ -26435,7 +26467,7 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req)
stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
if (p->owner) {
- sip_queue_hangup_cause(p, 0);
+ sip_queue_hangup_cause(p, ast_channel_hangupcause(p->owner));
} else {
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
}
@@ -26614,6 +26646,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
stop_session_timer(p); /* Stop Session-Timer */
}
+ use_reason_header(p, req);
if (!ast_strlen_zero(sip_get_header(req, "Also"))) {
ast_log(LOG_NOTICE, "Client '%s' using deprecated BYE/Also transfer method. Ask vendor to support REFER instead\n",
ast_sockaddr_stringify(&p->recv));
@@ -26654,7 +26687,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
ast_queue_hangup_with_cause(p->owner, AST_CAUSE_PROTOCOL_ERROR);
}
} else if (p->owner) {
- sip_queue_hangup_cause(p, 0);
+ sip_queue_hangup_cause(p, ast_channel_hangupcause(p->owner));
sip_scheddestroy_final(p, DEFAULT_TRANS_TIMEOUT);
ast_debug(3, "Received bye, issuing owner hangup\n");
} else {