Merged revisions 92158 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r92158 | oej | 2007-12-10 15:04:44 +0100 (MÃ¥n, 10 Dec 2007) | 16 lines Avoid reinvite race situations with two Asterisks trying to reinvite each other in 1.4 and trunk. This patch implements support for the 491 error code that Asterisk 1.4 generates on situations where we get an incoming INVITE and already has one in progress. Thanks to mavetju for reporting and to Raj Jain for an excellent explanation of the problem. Patch by myself. Tested with 8 Asterisk servers connected to each other in a training network. Closes issue #10481 ........ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@92159 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
ab9c1114a7
commit
648892798d
1 changed files with 37 additions and 10 deletions
|
@ -1132,6 +1132,7 @@ struct sip_pvt {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int initid; /*!< Auto-congest ID if appropriate (scheduler) */
|
int initid; /*!< Auto-congest ID if appropriate (scheduler) */
|
||||||
|
int waitid; /*!< Wait ID for scheduler after 491 or other delays */
|
||||||
int autokillid; /*!< Auto-kill ID (scheduler) */
|
int autokillid; /*!< Auto-kill ID (scheduler) */
|
||||||
enum transfermodes allowtransfer; /*!< REFER: restriction scheme */
|
enum transfermodes allowtransfer; /*!< REFER: restriction scheme */
|
||||||
struct sip_refer *refer; /*!< REFER: SIP transfer data structure */
|
struct sip_refer *refer; /*!< REFER: SIP transfer data structure */
|
||||||
|
@ -1691,7 +1692,7 @@ static int acf_channel_read(struct ast_channel *chan, const char *funcname, char
|
||||||
Functions for enabling debug per IP or fully, or enabling history logging for
|
Functions for enabling debug per IP or fully, or enabling history logging for
|
||||||
a SIP dialog
|
a SIP dialog
|
||||||
*/
|
*/
|
||||||
static void sip_dump_history(struct sip_pvt *dialog); /* Dump history to LOG_DEBUG at end of dialog, before destroying data */
|
static void sip_dump_history(struct sip_pvt *dialog); /* Dump history to debuglog at end of dialog, before destroying data */
|
||||||
static inline int sip_debug_test_addr(const struct sockaddr_in *addr);
|
static inline int sip_debug_test_addr(const struct sockaddr_in *addr);
|
||||||
static inline int sip_debug_test_pvt(struct sip_pvt *p);
|
static inline int sip_debug_test_pvt(struct sip_pvt *p);
|
||||||
static void append_history_full(struct sip_pvt *p, const char *fmt, ...);
|
static void append_history_full(struct sip_pvt *p, const char *fmt, ...);
|
||||||
|
@ -2464,8 +2465,7 @@ static int __sip_autodestruct(const void *data)
|
||||||
|
|
||||||
/* If there are packets still waiting for delivery, delay the destruction */
|
/* If there are packets still waiting for delivery, delay the destruction */
|
||||||
if (p->packets) {
|
if (p->packets) {
|
||||||
if (option_debug > 2)
|
ast_debug(3, "Re-scheduled destruction of SIP call %s\n", p->callid ? p->callid : "<unknown>");
|
||||||
ast_log(LOG_DEBUG, "Re-scheduled destruction of SIP call %s\n", p->callid ? p->callid : "<unknown>");
|
|
||||||
append_history(p, "ReliableXmit", "timeout");
|
append_history(p, "ReliableXmit", "timeout");
|
||||||
return 10000;
|
return 10000;
|
||||||
}
|
}
|
||||||
|
@ -3690,6 +3690,8 @@ static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
|
||||||
ast_extension_state_del(p->stateid, NULL);
|
ast_extension_state_del(p->stateid, NULL);
|
||||||
if (p->initid > -1)
|
if (p->initid > -1)
|
||||||
ast_sched_del(sched, p->initid);
|
ast_sched_del(sched, p->initid);
|
||||||
|
if (p->waitid > -1)
|
||||||
|
ast_sched_del(sched, p->waitid);
|
||||||
if (p->autokillid > -1)
|
if (p->autokillid > -1)
|
||||||
ast_sched_del(sched, p->autokillid);
|
ast_sched_del(sched, p->autokillid);
|
||||||
|
|
||||||
|
@ -4214,6 +4216,9 @@ static int sip_hangup(struct ast_channel *ast)
|
||||||
but we can't send one while we have "INVITE" outstanding. */
|
but we can't send one while we have "INVITE" outstanding. */
|
||||||
ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
|
ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
|
||||||
ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);
|
ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);
|
||||||
|
if (p->waitid)
|
||||||
|
ast_sched_del(sched, p->waitid);
|
||||||
|
p->waitid = -1;
|
||||||
sip_cancel_destroy(p);
|
sip_cancel_destroy(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5055,6 +5060,7 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
|
||||||
|
|
||||||
p->method = intended_method;
|
p->method = intended_method;
|
||||||
p->initid = -1;
|
p->initid = -1;
|
||||||
|
p->waitid = -1;
|
||||||
p->autokillid = -1;
|
p->autokillid = -1;
|
||||||
p->subscribed = NONE;
|
p->subscribed = NONE;
|
||||||
p->stateid = -1;
|
p->stateid = -1;
|
||||||
|
@ -13338,7 +13344,7 @@ static void check_pendings(struct sip_pvt *p)
|
||||||
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
|
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
|
||||||
} else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) {
|
} else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) {
|
||||||
/* if we can't REINVITE, hold it for later */
|
/* if we can't REINVITE, hold it for later */
|
||||||
if (p->pendinginvite || p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA) {
|
if (p->pendinginvite || p->invitestate == INV_CALLING || p->invitestate == INV_PROCEEDING || p->invitestate == INV_EARLY_MEDIA || p->waitid > 0) {
|
||||||
ast_debug(2, "NOT Sending pending reinvite (yet) on '%s'\n", p->callid);
|
ast_debug(2, "NOT Sending pending reinvite (yet) on '%s'\n", p->callid);
|
||||||
} else {
|
} else {
|
||||||
ast_debug(2, "Sending pending reinvite on '%s'\n", p->callid);
|
ast_debug(2, "Sending pending reinvite on '%s'\n", p->callid);
|
||||||
|
@ -13349,6 +13355,20 @@ static void check_pendings(struct sip_pvt *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \brief Reset the NEEDREINVITE flag after waiting when we get 491 on a Re-invite
|
||||||
|
to avoid race conditions between asterisk servers.
|
||||||
|
Called from the scheduler.
|
||||||
|
*/
|
||||||
|
static int sip_reinvite_retry(const void *data)
|
||||||
|
{
|
||||||
|
struct sip_pvt *p = (struct sip_pvt *) data;
|
||||||
|
|
||||||
|
ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
|
||||||
|
p->waitid = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! \brief Handle SIP response to INVITE dialogue */
|
/*! \brief Handle SIP response to INVITE dialogue */
|
||||||
static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
|
static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
|
||||||
{
|
{
|
||||||
|
@ -13639,13 +13659,20 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 491: /* Pending */
|
case 491: /* Pending */
|
||||||
/* we really should have to wait a while, then retransmit */
|
|
||||||
/* We should support the retry-after at some point */
|
|
||||||
/* At this point, we treat this as a congestion */
|
|
||||||
xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
|
xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
|
||||||
if (p->owner && !req->ignore)
|
if (p->owner && !req->ignore) {
|
||||||
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
|
if (p->owner->_state != AST_STATE_UP) {
|
||||||
p->needdestroy = 1;
|
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
|
||||||
|
p->needdestroy = 1;
|
||||||
|
} else {
|
||||||
|
/* This is a re-invite that failed. */
|
||||||
|
/* Reset the flag after a while
|
||||||
|
*/
|
||||||
|
int wait = 3 + ast_random() % 5;
|
||||||
|
p->waitid = ast_sched_add(sched, wait, sip_reinvite_retry, p);
|
||||||
|
ast_debug(2, "Reinvite race. Waiting %d secs before retry\n", wait);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 501: /* Not implemented */
|
case 501: /* Not implemented */
|
||||||
|
|
Reference in a new issue