*/
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) */
enum transfermodes allowtransfer; /*!< REFER: restriction scheme */
struct sip_refer *refer; /*!< REFER: SIP transfer data structure */
Functions for enabling debug per IP or fully, or enabling history logging for
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_pvt(struct sip_pvt *p);
static void append_history_full(struct sip_pvt *p, const char *fmt, ...);
/* If there are packets still waiting for delivery, delay the destruction */
if (p->packets) {
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Re-scheduled destruction of SIP call %s\n", p->callid ? p->callid : "<unknown>");
+ ast_debug(3, "Re-scheduled destruction of SIP call %s\n", p->callid ? p->callid : "<unknown>");
append_history(p, "ReliableXmit", "timeout");
return 10000;
}
ast_extension_state_del(p->stateid, NULL);
if (p->initid > -1)
ast_sched_del(sched, p->initid);
+ if (p->waitid > -1)
+ ast_sched_del(sched, p->waitid);
if (p->autokillid > -1)
ast_sched_del(sched, p->autokillid);
but we can't send one while we have "INVITE" outstanding. */
ast_set_flag(&p->flags[0], SIP_PENDINGBYE);
ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);
+ if (p->waitid)
+ ast_sched_del(sched, p->waitid);
+ p->waitid = -1;
sip_cancel_destroy(p);
}
}
p->method = intended_method;
p->initid = -1;
+ p->waitid = -1;
p->autokillid = -1;
p->subscribed = NONE;
p->stateid = -1;
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
} else if (ast_test_flag(&p->flags[0], SIP_NEEDREINVITE)) {
/* 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);
} else {
ast_debug(2, "Sending pending reinvite on '%s'\n", p->callid);
}
}
+/*! \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 */
static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno)
{
}
break;
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);
- if (p->owner && !req->ignore)
- ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
- p->needdestroy = 1;
+ if (p->owner && !req->ignore) {
+ if (p->owner->_state != AST_STATE_UP) {
+ 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;
case 501: /* Not implemented */