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 */
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;
pkt->next = p->packets;
pkt->owner = p;
pkt->seqno = seqno;
- if (resp)
- ast_set_flag(pkt, FLAG_RESPONSE);
pkt->data[len] = '\0';
+ if (resp) {
+ ast_set_flag(pkt, FLAG_RESPONSE);
+ /* 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)
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;