Merged revisions 204243,204246 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.4

........
  r204243 | mmichelson | 2009-06-29 16:23:43 -0500 (Mon, 29 Jun 2009) | 22 lines
  
  Fix a problem where chan_sip would ignore "old" but valid responses.
  
  chan_sip has had a problem for quite a long time that would manifest when
  Asterisk would send multiple SIP responses on the same dialog before receiving
  a response. The problem occurred because chan_sip only kept track of the highest
  outgoing sequence number used on the dialog. If Asterisk sent two requests out,
  and a response arrived for the first request sent, then Asterisk would ignore
  the response. The result was that Asterisk would continue retransmitting the
  requests and ignoring the responses until the maximum number of retransmissions
  had been reached.
  
  The fix here is to rearrange the code a bit so that instead of simply comparing
  the sequence number of the response to our latest outgoing sequence number, we
  walk our list of outstanding packets and determine if there is a match. If there is,
  we continue. If not, then we ignore the response.
  
  In doing this, I found a few completely useless variables that I have now removed.
  
  (closes issue #11231)
  Reported by: flefoll

  Review: https://reviewboard.asterisk.org/r/298
........
  r204246 | mmichelson | 2009-06-29 16:37:05 -0500 (Mon, 29 Jun 2009) | 3 lines
  
  Fix build oops.
........


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@204247 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Michelson 2009-06-29 21:48:54 +00:00
parent e840307ad1
commit 200f1dc19e

View file

@ -1751,7 +1751,6 @@ struct sip_pvt {
ast_group_t callgroup; /*!< Call group */ ast_group_t callgroup; /*!< Call group */
ast_group_t pickupgroup; /*!< Pickup group */ ast_group_t pickupgroup; /*!< Pickup group */
int lastinvite; /*!< Last Cseq of invite */ int lastinvite; /*!< Last Cseq of invite */
int lastnoninvite; /*!< Last Cseq of non-invite */
struct ast_flags flags[2]; /*!< SIP_ flags */ struct ast_flags flags[2]; /*!< SIP_ flags */
/* boolean flags that don't belong in flags */ /* boolean flags that don't belong in flags */
@ -2403,7 +2402,7 @@ static struct sip_pvt *sip_destroy(struct sip_pvt *p);
static void *dialog_unlink_all(struct sip_pvt *dialog, int lockowner, int lockdialoglist); static void *dialog_unlink_all(struct sip_pvt *dialog, int lockowner, int lockdialoglist);
static void *registry_unref(struct sip_registry *reg, char *tag); static void *registry_unref(struct sip_registry *reg, char *tag);
static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist); static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist);
static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod); static int __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
static void __sip_pretend_ack(struct sip_pvt *p); static void __sip_pretend_ack(struct sip_pvt *p);
static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod); static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod);
static int auto_congest(const void *arg); static int auto_congest(const void *arg);
@ -3891,10 +3890,11 @@ static int sip_cancel_destroy(struct sip_pvt *p)
/*! \brief Acknowledges receipt of a packet and stops retransmission /*! \brief Acknowledges receipt of a packet and stops retransmission
* called with p locked*/ * called with p locked*/
static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod) static int __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
{ {
struct sip_pkt *cur, *prev = NULL; struct sip_pkt *cur, *prev = NULL;
const char *msg = "Not Found"; /* used only for debugging */ const char *msg = "Not Found"; /* used only for debugging */
int res = FALSE;
/* If we have an outbound proxy for this dialog, then delete it now since /* If we have an outbound proxy for this dialog, then delete it now since
the rest of the requests in this dialog needs to follow the routing. the rest of the requests in this dialog needs to follow the routing.
@ -3909,6 +3909,7 @@ static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
if (cur->seqno != seqno || cur->is_resp != resp) if (cur->seqno != seqno || cur->is_resp != resp)
continue; continue;
if (cur->is_resp || cur->method == sipmethod) { if (cur->is_resp || cur->method == sipmethod) {
res = TRUE;
msg = "Found"; msg = "Found";
if (!resp && (seqno == p->pendinginvite)) { if (!resp && (seqno == p->pendinginvite)) {
ast_debug(1, "Acked pending invite %d\n", p->pendinginvite); ast_debug(1, "Acked pending invite %d\n", p->pendinginvite);
@ -3949,6 +3950,7 @@ static void __sip_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
} }
ast_debug(1, "Stopping retransmission on '%s' of %s %d: Match %s\n", ast_debug(1, "Stopping retransmission on '%s' of %s %d: Match %s\n",
p->callid, resp ? "Response" : "Request", seqno, msg); p->callid, resp ? "Response" : "Request", seqno, msg);
return res;
} }
/*! \brief Pretend to ack all packets /*! \brief Pretend to ack all packets
@ -3973,7 +3975,7 @@ static void __sip_pretend_ack(struct sip_pvt *p)
static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod) static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
{ {
struct sip_pkt *cur; struct sip_pkt *cur;
int res = -1; int res = FALSE;
for (cur = p->packets; cur; cur = cur->next) { for (cur = p->packets; cur; cur = cur->next) {
if (cur->seqno == seqno && cur->is_resp == resp && if (cur->seqno == seqno && cur->is_resp == resp &&
@ -3984,7 +3986,7 @@ static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp, int sipmethod)
ast_debug(4, "*** SIP TIMER: Cancelling retransmission #%d - %s (got response)\n", cur->retransid, sip_methods[sipmethod].text); ast_debug(4, "*** SIP TIMER: Cancelling retransmission #%d - %s (got response)\n", cur->retransid, sip_methods[sipmethod].text);
} }
AST_SCHED_DEL(sched, cur->retransid); AST_SCHED_DEL(sched, cur->retransid);
res = 0; res = TRUE;
break; break;
} }
} }
@ -11215,8 +11217,6 @@ static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *messa
if (!p->initreq.headers) if (!p->initreq.headers)
initialize_initreq(p, &req); initialize_initreq(p, &req);
p->lastnoninvite = p->ocseq;
return send_request(p, &req, XMIT_RELIABLE, p->ocseq); return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
} }
@ -18535,6 +18535,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
struct ast_channel *owner; struct ast_channel *owner;
int sipmethod; int sipmethod;
int res = 1; int res = 1;
int ack_res;
const char *c = get_header(req, "Cseq"); const char *c = get_header(req, "Cseq");
/* GCC 4.2 complains if I try to cast c as a char * when passing it to ast_skip_nonblanks, so make a copy of it */ /* GCC 4.2 complains if I try to cast c as a char * when passing it to ast_skip_nonblanks, so make a copy of it */
char *c_copy = ast_strdupa(c); char *c_copy = ast_strdupa(c);
@ -18552,10 +18553,16 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc
owner->hangupcause = hangup_sip2cause(resp); owner->hangupcause = hangup_sip2cause(resp);
/* Acknowledge whatever it is destined for */ /* Acknowledge whatever it is destined for */
if ((resp >= 100) && (resp <= 199)) if ((resp >= 100) && (resp <= 199)) {
__sip_semi_ack(p, seqno, 0, sipmethod); ack_res = __sip_semi_ack(p, seqno, 0, sipmethod);
else } else {
__sip_ack(p, seqno, 0, sipmethod); ack_res = __sip_ack(p, seqno, 0, sipmethod);
}
if (ack_res == FALSE) {
append_history(p, "Ignore", "Ignoring this retransmit\n");
return;
}
/* If this is a NOTIFY for a subscription clear the flag that indicates that we have a NOTIFY pending */ /* If this is a NOTIFY for a subscription clear the flag that indicates that we have a NOTIFY pending */
if (!p->owner && sipmethod == SIP_NOTIFY && p->pendinginvite) if (!p->owner && sipmethod == SIP_NOTIFY && p->pendinginvite)
@ -21938,7 +21945,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct so
/* Get the command XXX */ /* Get the command XXX */
cmd = REQ_OFFSET_TO_STR(req, rlPart1); cmd = REQ_OFFSET_TO_STR(req, rlPart1);
e = REQ_OFFSET_TO_STR(req, rlPart2); e = ast_skip_blanks(REQ_OFFSET_TO_STR(req, rlPart2));
/* Save useragent of the client */ /* Save useragent of the client */
useragent = get_header(req, "User-Agent"); useragent = get_header(req, "User-Agent");
@ -21947,40 +21954,32 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct so
/* Find out SIP method for incoming request */ /* Find out SIP method for incoming request */
if (req->method == SIP_RESPONSE) { /* Response to our request */ if (req->method == SIP_RESPONSE) { /* Response to our request */
/* When we get here, we know this is a SIP dialog where we've sent /* ignore means "don't do anything with it" but still have to
* a request and have a response, or at least get a response * respond appropriately.
* within an existing dialog. Do some sanity checks, then * But in this case this is a response already, so we really
* possibly process the request. In all cases, there function * have nothing to do with this message, and even setting the
* terminates at the end of this block * ignore flag is pointless.
*/ */
int ret = 0; if (ast_strlen_zero(e)) {
return 0;
if (p->ocseq < seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) { }
ast_debug(1, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq); if (sscanf(e, "%d %n", &respid, &len) != 1) {
ret = -1; ast_log(LOG_WARNING, "Invalid response: '%s'\n", e);
} else if (p->ocseq != seqno && p->lastinvite != seqno && p->lastnoninvite != seqno) { return 0;
/* ignore means "don't do anything with it" but still have to }
* respond appropriately. if (respid <= 0) {
* But in this case this is a response already, so we really ast_log(LOG_WARNING, "Invalid SIP response code: '%d'\n", respid);
* have nothing to do with this message, and even setting the return 0;
* ignore flag is pointless. }
*/ if (p->ocseq && (p->ocseq < seqno)) {
req->ignore = 1; if (option_debug)
append_history(p, "Ignore", "Ignoring this retransmit\n"); ast_log(LOG_DEBUG, "Ignoring out of order response %d (expecting %d)\n", seqno, p->ocseq);
} else if (e) { return -1;
e = ast_skip_blanks(e); } else {
if (sscanf(e, "%d %n", &respid, &len) != 1) { if ((respid == 200) || ((respid >= 300) && (respid <= 399))) {
ast_log(LOG_WARNING, "Invalid response: '%s'\n", e); extract_uri(p, req);
/* XXX maybe should do ret = -1; */
} else if (respid <= 0) {
ast_log(LOG_WARNING, "Invalid SIP response code: '%d'\n", respid);
/* XXX maybe should do ret = -1; */
} else { /* finally, something worth processing */
/* More SIP ridiculousness, we have to ignore bogus contacts in 100 etc responses */
if ((respid == 200) || ((respid >= 300) && (respid <= 399)))
extract_uri(p, req);
handle_response(p, respid, e + len, req, seqno);
} }
handle_response(p, respid, e + len, req, seqno);
} }
return 0; return 0;
} }