Allow expiration of several messages to be non-fatal.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@2550 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer
2004-03-24 21:21:59 +00:00
parent f8b04c4bb6
commit b43c1f054b

View File

@@ -281,11 +281,14 @@ static struct sip_pvt {
struct sip_pvt *next; struct sip_pvt *next;
} *iflist = NULL; } *iflist = NULL;
#define FLAG_RESPONSE (1 << 0)
#define FLAG_FATAL (1 << 1)
struct sip_pkt { struct sip_pkt {
struct sip_pkt *next; /* Next packet */ struct sip_pkt *next; /* Next packet */
int retrans; /* Retransmission number */ int retrans; /* Retransmission number */
int seqno; /* Sequence number */ int seqno; /* Sequence number */
int resp; /* non-zero if this is a response packet (e.g. 200 OK) */ int flags; /* non-zero if this is a response packet (e.g. 200 OK) */
struct sip_pvt *owner; /* Owner call */ struct sip_pvt *owner; /* Owner call */
int retransid; /* Retransmission ID */ int retransid; /* Retransmission ID */
int packetlen; /* Length of packet */ int packetlen; /* Length of packet */
@@ -494,20 +497,25 @@ static int retrans_pkt(void *data)
__sip_xmit(pkt->owner, pkt->data, pkt->packetlen); __sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
res = 1; res = 1;
} else { } else {
ast_log(LOG_WARNING, "Maximum retries exceeded on call %s for seqno %d (%s)\n", pkt->owner->callid, pkt->seqno, pkt->resp ? "Response" : "Request"); ast_log(LOG_WARNING, "Maximum retries exceeded on call %s for seqno %d (%s %s)\n", pkt->owner->callid, pkt->seqno, (pkt->flags & FLAG_FATAL) ? "Critical" : "Non-critical", (pkt->flags & FLAG_RESPONSE) ? "Response" : "Request");
pkt->retransid = -1; pkt->retransid = -1;
while(pkt->owner->owner && ast_mutex_trylock(&pkt->owner->owner->lock)) { if (pkt->flags & FLAG_FATAL) {
ast_mutex_unlock(&pkt->owner->lock); while(pkt->owner->owner && ast_mutex_trylock(&pkt->owner->owner->lock)) {
usleep(1); ast_mutex_unlock(&pkt->owner->lock);
ast_mutex_lock(&pkt->owner->lock); usleep(1);
} ast_mutex_lock(&pkt->owner->lock);
if (pkt->owner->owner) { }
/* XXX Potential deadlocK?? XXX */ if (pkt->owner->owner) {
ast_queue_hangup(pkt->owner->owner, 0); /* XXX Potential deadlocK?? XXX */
ast_mutex_unlock(&pkt->owner->owner->lock); ast_queue_hangup(pkt->owner->owner, 0);
ast_mutex_unlock(&pkt->owner->owner->lock);
} else {
/* If no owner, destroy now */
pkt->owner->needdestroy = 1;
}
} else { } else {
/* If no owner, destroy now */ /* Okay, it's not fatal, just continue. XXX If we were nice, we'd free it now, rather than wait for the
pkt->owner->needdestroy = 1; end of the call XXX */
} }
} }
if (pkt) if (pkt)
@@ -515,7 +523,7 @@ static int retrans_pkt(void *data)
return res; return res;
} }
static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len) static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal)
{ {
struct sip_pkt *pkt; struct sip_pkt *pkt;
pkt = malloc(sizeof(struct sip_pkt) + len); pkt = malloc(sizeof(struct sip_pkt) + len);
@@ -527,7 +535,9 @@ static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *dat
pkt->next = p->packets; pkt->next = p->packets;
pkt->owner = p; pkt->owner = p;
pkt->seqno = seqno; pkt->seqno = seqno;
pkt->resp = resp; pkt->flags = resp;
if (fatal)
pkt->flags |= FLAG_FATAL;
/* Schedule retransmission */ /* Schedule retransmission */
pkt->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, pkt); pkt->retransid = ast_sched_add(sched, DEFAULT_RETRANS, retrans_pkt, pkt);
pkt->next = p->packets; pkt->next = p->packets;
@@ -577,7 +587,7 @@ static int __sip_ack(struct sip_pvt *p, int seqno, int resp)
int resetinvite = 0; int resetinvite = 0;
cur = p->packets; cur = p->packets;
while(cur) { while(cur) {
if ((cur->seqno == seqno) && (cur->resp == resp)) { if ((cur->seqno == seqno) && ((cur->flags & FLAG_RESPONSE) == resp)) {
if (!resp && (seqno == p->pendinginvite)) { if (!resp && (seqno == p->pendinginvite)) {
ast_log(LOG_DEBUG, "Acked pending invite %d\n", p->pendinginvite); ast_log(LOG_DEBUG, "Acked pending invite %d\n", p->pendinginvite);
p->pendinginvite = 0; p->pendinginvite = 0;
@@ -607,7 +617,7 @@ static int __sip_semi_ack(struct sip_pvt *p, int seqno, int resp)
int res = -1; int res = -1;
cur = p->packets; cur = p->packets;
while(cur) { while(cur) {
if ((cur->seqno == seqno) && (cur->resp == resp)) { if ((cur->seqno == seqno) && ((cur->flags & FLAG_RESPONSE) == resp)) {
/* this is our baby */ /* this is our baby */
if (cur->retransid > -1) if (cur->retransid > -1)
ast_sched_del(sched, cur->retransid); ast_sched_del(sched, cur->retransid);
@@ -631,7 +641,7 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, int reliabl
ast_verbose("%sTransmitting (no NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port)); ast_verbose("%sTransmitting (no NAT):\n%s\n to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port));
} }
if (reliable) if (reliable)
res = __sip_reliable_xmit(p, seqno, 1, req->data, req->len); res = __sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable > 1));
else else
res = __sip_xmit(p, req->data, req->len); res = __sip_xmit(p, req->data, req->len);
if (res > 0) if (res > 0)
@@ -649,7 +659,7 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, int reliable
ast_verbose("%sTransmitting:\n%s (no NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port)); ast_verbose("%sTransmitting:\n%s (no NAT) to %s:%d\n", reliable ? "Reliably " : "", req->data, inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port));
} }
if (reliable) if (reliable)
res = __sip_reliable_xmit(p, seqno, 0, req->data, req->len); res = __sip_reliable_xmit(p, seqno, 0, req->data, req->len, (reliable > 1));
else else
res = __sip_xmit(p, req->data, req->len); res = __sip_xmit(p, req->data, req->len);
return res; return res;
@@ -1184,7 +1194,7 @@ static void sip_destroy(struct sip_pvt *p)
ast_mutex_unlock(&iflock); ast_mutex_unlock(&iflock);
} }
static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req); static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req, int fatal);
static int hangup_sip2cause(int cause) static int hangup_sip2cause(int cause)
{ {
@@ -1275,9 +1285,9 @@ static int sip_hangup(struct ast_channel *ast)
} else { } else {
char *res; char *res;
if (ast->hangupcause && ((res = hangup_cause2sip(ast->hangupcause)))) { if (ast->hangupcause && ((res = hangup_cause2sip(ast->hangupcause)))) {
transmit_response_reliable(p, res, &p->initreq); transmit_response_reliable(p, res, &p->initreq, 1);
} else } else
transmit_response_reliable(p, "403 Forbidden", &p->initreq); transmit_response_reliable(p, "403 Forbidden", &p->initreq, 1);
} }
} else { } else {
if (!p->pendinginvite) { if (!p->pendinginvite) {
@@ -2526,9 +2536,9 @@ static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *r
{ {
return __transmit_response(p, msg, req, 0); return __transmit_response(p, msg, req, 0);
} }
static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req) static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req, int fatal)
{ {
return __transmit_response(p, msg, req, 1); return __transmit_response(p, msg, req, fatal ? 2 : 1);
} }
static void append_date(struct sip_request *req) static void append_date(struct sip_request *req)
@@ -3029,7 +3039,7 @@ static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, ch
determine_firstline_parts(&p->initreq); determine_firstline_parts(&p->initreq);
} }
p->lastinvite = p->ocseq; p->lastinvite = p->ocseq;
return send_request(p, &req, 1, p->ocseq); return send_request(p, &req, init ? 2 : 1, p->ocseq);
} }
static int transmit_state_notify(struct sip_pvt *p, int state, int full) static int transmit_state_notify(struct sip_pvt *p, int state, int full)
@@ -3296,7 +3306,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
parse(&p->initreq); parse(&p->initreq);
determine_firstline_parts(&p->initreq); determine_firstline_parts(&p->initreq);
r->regstate=auth?REG_STATE_AUTHSENT:REG_STATE_REGSENT; r->regstate=auth?REG_STATE_AUTHSENT:REG_STATE_REGSENT;
return send_request(p, &req, 1, p->ocseq); return send_request(p, &req, 2, p->ocseq);
} }
static int transmit_message_with_text(struct sip_pvt *p, char *text) static int transmit_message_with_text(struct sip_pvt *p, char *text)
@@ -5411,14 +5421,14 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
ast_mutex_unlock(&p->lock); ast_mutex_unlock(&p->lock);
ast_hangup(c); ast_hangup(c);
ast_mutex_lock(&p->lock); ast_mutex_lock(&p->lock);
transmit_response_reliable(p, "503 Unavailable", req); transmit_response_reliable(p, "503 Unavailable", req, 1);
c = NULL; c = NULL;
} }
} else { } else {
ast_mutex_unlock(&c->lock); ast_mutex_unlock(&c->lock);
if (ast_pickup_call(c)) { if (ast_pickup_call(c)) {
ast_log(LOG_NOTICE, "Nothing to pick up\n"); ast_log(LOG_NOTICE, "Nothing to pick up\n");
transmit_response_reliable(p, "503 Unavailable", req); transmit_response_reliable(p, "503 Unavailable", req, 1);
p->alreadygone = 1; p->alreadygone = 1;
/* Unlock locks so ast_hangup can do its magic */ /* Unlock locks so ast_hangup can do its magic */
ast_mutex_unlock(&p->lock); ast_mutex_unlock(&p->lock);
@@ -5450,7 +5460,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
} else { } else {
if (p && !p->needdestroy) { if (p && !p->needdestroy) {
ast_log(LOG_NOTICE, "Unable to create/find channel\n"); ast_log(LOG_NOTICE, "Unable to create/find channel\n");
transmit_response_reliable(p, "503 Unavailable", req); transmit_response_reliable(p, "503 Unavailable", req, 1);
p->needdestroy = 1; p->needdestroy = 1;
} }
} }
@@ -5505,10 +5515,10 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
else else
p->needdestroy = 1; p->needdestroy = 1;
if (p->initreq.len > 0) { if (p->initreq.len > 0) {
transmit_response_reliable(p, "487 Request Terminated", &p->initreq); transmit_response_reliable(p, "487 Request Terminated", &p->initreq, 1);
transmit_response(p, "200 OK", req); transmit_response(p, "200 OK", req);
} else { } else {
transmit_response_reliable(p, "481 Call Leg Does Not Exist", req); transmit_response_reliable(p, "481 Call Leg Does Not Exist", req, 1);
} }
} else if (!strcasecmp(cmd, "BYE")) { } else if (!strcasecmp(cmd, "BYE")) {
copy_request(&p->initreq, req); copy_request(&p->initreq, req);
@@ -5638,7 +5648,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
/* Uhm, I haven't figured out the point of the ACK yet. Are we /* Uhm, I haven't figured out the point of the ACK yet. Are we
supposed to retransmit responses until we get an ack? supposed to retransmit responses until we get an ack?
Make sure this is on a valid call */ Make sure this is on a valid call */
__sip_ack(p, seqno, 1); __sip_ack(p, seqno, FLAG_RESPONSE);
if (strlen(get_header(req, "Content-Type"))) { if (strlen(get_header(req, "Content-Type"))) {
if (process_sdp(p, req)) if (process_sdp(p, req))
return -1; return -1;