[asterisk-commits] twilson: branch 1.6.0 r215759 - /branches/1.6.0/channels/chan_sip.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Sep 2 19:05:19 CDT 2009
Author: twilson
Date: Wed Sep 2 19:05:11 2009
New Revision: 215759
URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=215759
Log:
Merged revisions 215758 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk
................
r215758 | twilson | 2009-09-02 18:31:04 -0500 (Wed, 02 Sep 2009) | 25 lines
Merged revisions 215682 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r215682 | twilson | 2009-09-02 16:41:22 -0500 (Wed, 02 Sep 2009) | 18 lines
Re-send non-100 provisional responses to prevent cancellation
From section 13.3.1.1 of RFC 3261:
If the UAS desires an extended period of time to answer the INVITE,
it will need to ask for an "extension" in order to prevent proxies
from canceling the transaction. A proxy has the option of canceling
a transaction when there is a gap of 3 minutes between responses in a
transaction. To prevent cancellation, the UAS MUST send a non-100
provisional response at every minute, to handle the possibility of
lost provisional responses.
(closes issue #11157)
Reported by: rjain
Tested by: twilson
Review: https://reviewboard.asterisk.org/r/315/
........
................
Modified:
branches/1.6.0/channels/chan_sip.c
Modified: branches/1.6.0/channels/chan_sip.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.0/channels/chan_sip.c?view=diff&rev=215759&r1=215758&r2=215759
==============================================================================
--- branches/1.6.0/channels/chan_sip.c (original)
+++ branches/1.6.0/channels/chan_sip.c Wed Sep 2 19:05:11 2009
@@ -235,6 +235,7 @@
\todo Use known T1 for timeout (peerpoke)
*/
#define DEFAULT_TRANS_TIMEOUT -1 /* Use default SIP transaction timeout */
+#define PROVIS_KEEPALIVE_TIMEOUT 60000 /*!< How long to wait before retransmitting a provisional response (rfc 3261 13.3.1.1) */
#define MAX_AUTHTRIES 3 /*!< Try authentication three times, then fail */
#define SIP_MAX_HEADERS 64 /*!< Max amount of SIP headers to read */
@@ -1281,6 +1282,8 @@
struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
AST_LIST_HEAD_NOLOCK(request_queue, sip_request) request_queue; /*!< Requests that arrived but could not be processed immediately */
int request_queue_sched_id; /*!< Scheduler ID of any scheduled action to process queued requests */
+ int provisional_keepalive_sched_id; /*!< Scheduler ID for provisional responses that need to be sent out to avoid cancellation */
+ const char *last_provisional; /*!< The last successfully transmitted provisonal response message */
struct sip_invite_param *options; /*!< Options for INVITE */
int autoframing; /*!< The number of Asters we group in a Pyroflax
before strolling to the Grokyzpå
@@ -1736,6 +1739,7 @@
static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable, int oldsdp);
static int transmit_response_with_unsupported(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *unsupported);
static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const struct sip_request *req, const char *rand, enum xmittype reliable, const char *header, int stale);
+static int transmit_provisional_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, int with_sdp);
static int transmit_response_with_allow(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable);
static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct sip_request *req, enum xmittype reliable);
static int transmit_request(struct sip_pvt *p, int sipmethod, int inc, enum xmittype reliable, int newbranch);
@@ -3282,6 +3286,46 @@
}
}
+static int send_provisional_keepalive_full(struct sip_pvt *pvt, int with_sdp)
+{
+ const char *msg = NULL;
+
+ if (!pvt->last_provisional || !strncasecmp(pvt->last_provisional, "100", 3)) {
+ msg = "183 Session Progress";
+ }
+
+ if (pvt->invitestate < INV_COMPLETED) {
+ if (with_sdp) {
+ transmit_response_with_sdp(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq, XMIT_UNRELIABLE, FALSE);
+ } else {
+ transmit_response(pvt, S_OR(msg, pvt->last_provisional), &pvt->initreq);
+ }
+ return PROVIS_KEEPALIVE_TIMEOUT;
+ }
+
+ return 0;
+}
+
+static int send_provisional_keepalive(const void *data) {
+ struct sip_pvt *pvt = (struct sip_pvt *) data;
+
+ return send_provisional_keepalive_full(pvt, 0);
+}
+
+static int send_provisional_keepalive_with_sdp(const void *data) {
+ struct sip_pvt *pvt = (void *)data;
+
+ return send_provisional_keepalive_full(pvt, 1);
+}
+
+static void update_provisional_keepalive(struct sip_pvt *pvt, int with_sdp)
+{
+ AST_SCHED_DEL(sched, pvt->provisional_keepalive_sched_id);
+
+ pvt->provisional_keepalive_sched_id = ast_sched_add(sched, PROVIS_KEEPALIVE_TIMEOUT,
+ with_sdp ? send_provisional_keepalive_with_sdp : send_provisional_keepalive, pvt);
+}
+
/*! \brief Transmit response on SIP request*/
static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno)
{
@@ -3302,6 +3346,12 @@
append_history(p, reliable ? "TxRespRel" : "TxResp", "%s / %s - %s", tmp.data, get_header(&tmp, "CSeq"),
(tmp.method == SIP_RESPONSE || tmp.method == SIP_UNKNOWN) ? tmp.rlPart2 : sip_methods[tmp.method].text);
}
+
+ /* If we are sending a final response to an INVITE, stop retransmitting provisional responses */
+ if (p->initreq.method == SIP_INVITE && reliable == XMIT_CRITICAL) {
+ AST_SCHED_DEL(sched, p->provisional_keepalive_sched_id);
+ }
+
res = (reliable) ?
__sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable == XMIT_CRITICAL), req->method) :
__sip_xmit(p, req->data, req->len);
@@ -4575,6 +4625,7 @@
AST_SCHED_DEL(sched, p->waitid);
AST_SCHED_DEL(sched, p->autokillid);
AST_SCHED_DEL(sched, p->request_queue_sched_id);
+ AST_SCHED_DEL(sched, p->provisional_keepalive_sched_id);
AST_SCHED_DEL(sched, p->t38id);
if (p->rtp) {
@@ -5247,7 +5298,7 @@
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
ast_rtp_new_source(p->rtp);
p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
+ transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
} else if (p->t38.state == T38_ENABLED) {
change_t38_state(p, T38_DISABLED);
@@ -5269,7 +5320,7 @@
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
+ transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
}
p->lastrtptx = time(NULL);
@@ -5287,7 +5338,7 @@
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
+ transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
}
p->lastrtptx = time(NULL);
@@ -5500,7 +5551,7 @@
if (!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) ||
(ast_test_flag(&p->flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) {
/* Send 180 ringing if out-of-band seems reasonable */
- transmit_response(p, "180 Ringing", &p->initreq);
+ transmit_provisional_response(p, "180 Ringing", &p->initreq, 0);
ast_set_flag(&p->flags[0], SIP_RINGING);
if (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) != SIP_PROG_INBAND_YES)
break;
@@ -5545,7 +5596,7 @@
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
!ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
p->invitestate = INV_EARLY_MEDIA;
- transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE, FALSE);
+ transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE);
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
break;
}
@@ -6118,6 +6169,7 @@
p->waitid = -1;
p->autokillid = -1;
p->request_queue_sched_id = -1;
+ p->provisional_keepalive_sched_id = -1;
p->t38id = -1;
p->subscribed = NONE;
p->stateid = -1;
@@ -8268,6 +8320,19 @@
add_header_contentLength(&resp, 0);
append_history(p, "AuthChal", "Auth challenge sent for %s - nc %d", p->username, p->noncecount);
return send_response(p, &resp, reliable, seqno);
+}
+
+/* Only use a static string for the msg, here! */
+static int transmit_provisional_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, int with_sdp)
+{
+ int res;
+
+ if (!(res = with_sdp ? transmit_response_with_sdp(p, msg, req, XMIT_UNRELIABLE, FALSE) : transmit_response(p, msg, req))) {
+ p->last_provisional = msg;
+ update_provisional_keepalive(p, with_sdp);
+ }
+
+ return res;
}
/*! \brief Add text body to SIP message */
@@ -17878,7 +17943,7 @@
switch(c_state) {
case AST_STATE_DOWN:
ast_debug(2, "%s: New call is still down.... Trying... \n", c->name);
- transmit_response(p, "100 Trying", req);
+ transmit_provisional_response(p, "100 Trying", req, FALSE);
p->invitestate = INV_PROCEEDING;
ast_setstate(c, AST_STATE_RING);
if (strcmp(p->exten, ast_pickup_ext())) { /* Call to extension -start pbx on this call */
@@ -17933,11 +17998,11 @@
}
break;
case AST_STATE_RING:
- transmit_response(p, "100 Trying", req);
+ transmit_provisional_response(p, "100 Trying", req, 0);
p->invitestate = INV_PROCEEDING;
break;
case AST_STATE_RINGING:
- transmit_response(p, "180 Ringing", req);
+ transmit_provisional_response(p, "180 Ringing", req, 0);
p->invitestate = INV_PROCEEDING;
break;
case AST_STATE_UP:
More information about the asterisk-commits
mailing list