Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 201443) +++ channels/chan_sip.c (working copy) @@ -1048,6 +1048,7 @@ int retrans; /*!< Retransmission number */ int method; /*!< SIP method for this packet */ int seqno; /*!< Sequence number */ + int response_code; /*!< If this is a response, the response code */ unsigned int flags; /*!< non-zero if this is a response packet (e.g. 200 OK) */ struct sip_pvt *owner; /*!< Owner AST call */ int retransid; /*!< Retransmission ID */ @@ -2052,6 +2053,7 @@ struct sip_pkt *pkt; int siptimer_a = DEFAULT_RETRANS; int xmitres = 0; + int respid; if (!(pkt = ast_calloc(1, sizeof(*pkt) + len + 1))) return AST_FAILURE; @@ -2061,9 +2063,15 @@ pkt->next = p->packets; pkt->owner = p; pkt->seqno = seqno; - if (resp) + pkt->data[len] = '\0'; + if (resp) { ast_set_flag(pkt, FLAG_RESPONSE); - pkt->data[len] = '\0'; + /* Parse out the response code */ + if (sscanf(pkt->data, "SIP/2.0 %d", &respid) == 1) { + pkt->response_code = respid; + ast_log(LOG_NOTICE, "Hey, I just set the response code for this packet to %d\n", pkt->response_code); + } + } pkt->timer_t1 = p->timer_t1; /* Set SIP timer T1 */ pkt->retransid = -1; if (fatal) @@ -15480,6 +15488,30 @@ else sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); if (p->initreq.len > 0) { + struct sip_pkt *pkt, *prev_pkt; + /* If the CANCEL we are receiving is a retransmission, and we already have scheduled + * a reliable 487, then we don't want to schedule another one on top of the previous + * one. + * + * As odd as this may sound, we can't rely on the previously-transmitted "reliable" + * response in this situation. What if we've sent all of our reliable responses + * already and now all of a sudden, we get this second CANCEL? + * + * The only way to do this correctly is to cancel our previously-scheduled reliably- + * transmitted response and send a new one in its place. + */ + for (pkt = p->packets, prev_pkt = NULL; pkt; prev_pkt = pkt, pkt = pkt->next) { + if (pkt->seqno == p->lastinvite && pkt->response_code == 487) { + AST_SCHED_DEL(sched, pkt->retransid); + if (prev_pkt) { + prev_pkt->next = pkt->next; + } else { + p->packets = pkt->next; + } + ast_free(pkt); + break; + } + } transmit_response_reliable(p, "487 Request Terminated", &p->initreq); transmit_response(p, "200 OK", req); return 1;