factor out INVITE response handling in its own function (issue #5127)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6532 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Kevin P. Fleming 2005-09-07 19:00:31 +00:00
parent 721bd0aa59
commit 1bd1a35a9a

View file

@ -8893,6 +8893,148 @@ static void check_pendings(struct sip_pvt *p)
}
}
/*--- handle_response_invite: Handle SIP response in dialogue ---*/
static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno)
{
int outgoing = ast_test_flag(p, SIP_OUTGOING);
if (option_debug > 3) {
int reinvite = (p->owner && p->owner->_state == AST_STATE_UP);
if (reinvite)
ast_log(LOG_DEBUG, "SIP response %d to RE-invite on %s call %s\n", resp, outgoing ? "outgoing" : "incoming", p->callid);
else
ast_log(LOG_DEBUG, "SIP response %d to standard invite", resp);
}
switch (resp) {
case 100: /* Trying */
sip_cancel_destroy(p);
case 180: /* 180 Ringing */
sip_cancel_destroy(p);
if (!ignore && p->owner) {
ast_queue_control(p->owner, AST_CONTROL_RINGING);
if (p->owner->_state != AST_STATE_UP)
ast_setstate(p->owner, AST_STATE_RINGING);
}
if (!strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
process_sdp(p, req);
if (!ignore && p->owner) {
/* Queue a progress frame only if we have SDP in 180 */
ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
}
}
break;
case 183: /* Session progress */
sip_cancel_destroy(p);
if (!strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
process_sdp(p, req);
}
if (!ignore && p->owner) {
/* Queue a progress frame */
ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
}
break;
case 200: /* 200 OK on invite - someone's answering our call */
sip_cancel_destroy(p);
p->authtries = 0;
if (!strcasecmp(get_header(req, "Content-Type"), "application/sdp")) {
process_sdp(p, req);
}
/* Parse contact header for continued conversation */
/* When we get 200 OK, we know which device (and IP) to contact for this call */
/* This is important when we have a SIP proxy between us and the phone */
if (outgoing) {
parse_ok_contact(p, req);
/* Save Record-Route for any later requests we make on this dialogue */
build_route(p, req, 1);
}
if (!ignore && p->owner) {
if (p->owner->_state != AST_STATE_UP) {
#ifdef OSP_SUPPORT
time(&p->ospstart);
#endif
ast_queue_control(p->owner, AST_CONTROL_ANSWER);
} else { /* RE-invite */
struct ast_frame af = { AST_FRAME_NULL, };
ast_queue_frame(p->owner, &af);
}
} else {
/* It's possible we're getting an ACK after we've tried to disconnect
by sending CANCEL */
/* THIS NEEDS TO BE CHECKED: OEJ */
if (!ignore)
ast_set_flag(p, SIP_PENDINGBYE);
}
/* If I understand this right, the branch is different for a non-200 ACK only */
transmit_request(p, SIP_ACK, seqno, 0, 1);
check_pendings(p);
break;
case 401: /* Www auth */
/* First we ACK */
transmit_request(p, SIP_ACK, seqno, 0, 0);
/* Then we AUTH */
p->theirtag[0]='\0'; /* forget their old tag, so we don't match tags when getting response */
if (!ignore) {
if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, "WWW-Authenticate", "Authorization", SIP_INVITE, 1)) {
ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
ast_set_flag(p, SIP_NEEDDESTROY);
ast_set_flag(p, SIP_ALREADYGONE);
if (p->owner)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
}
}
break;
case 403: /* Forbidden */
/* First we ACK */
transmit_request(p, SIP_ACK, seqno, 0, 0);
ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for INVITE to '%s'\n", get_header(&p->initreq, "From"));
if (!ignore && p->owner)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
ast_set_flag(p, SIP_NEEDDESTROY);
ast_set_flag(p, SIP_ALREADYGONE);
break;
case 404: /* Not found */
transmit_request(p, SIP_ACK, seqno, 0, 0);
if (p->owner && !ignore)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
ast_set_flag(p, SIP_ALREADYGONE);
break;
case 407: /* Proxy authentication */
/* First we ACK */
transmit_request(p, SIP_ACK, seqno, 0, 0);
/* Then we AUTH */
/* But only if the packet wasn't marked as ignore in handle_request */
if (!ignore) {
p->theirtag[0]='\0'; /* forget their old tag, so we don't match tags when getting response */
if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", SIP_INVITE, 1)) {
ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
ast_set_flag(p, SIP_NEEDDESTROY);
if (p->owner)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
ast_set_flag(p, SIP_ALREADYGONE);
}
}
break;
case 481: /* Call leg does not exist */
/* Could be REFER or INVITE */
ast_log(LOG_WARNING, "Re-invite to non-existing call leg on other UA. SIP dialog '%s'. Giving up.\n", p->callid);
transmit_request(p, SIP_ACK, seqno, 0, 0);
break;
case 491: /* Pending */
/* we have to wait a while, then retransmit */
/* Transmission is rescheduled, so everything should be taken care of.
We should support the retry-after at some point */
break;
case 501: /* Not implemented */
if (p->owner)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
break;
}
}
/*--- handle_response_register: Handle responses on REGISTER to services ---*/
static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int ignore, int seqno)
{
@ -9116,30 +9258,16 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
}
switch(resp) {
case 100: /* 100 Trying */
if (sipmethod == SIP_INVITE) {
sip_cancel_destroy(p);
}
if (sipmethod == SIP_INVITE)
handle_response_invite(p, resp, rest, req, ignore, seqno);
break;
case 183: /* 183 Session Progress */
if (sipmethod == SIP_INVITE) {
sip_cancel_destroy(p);
if (!ast_strlen_zero(get_header(req, "Content-Type")))
process_sdp(p, req);
if (p->owner) {
/* Queue a progress frame */
ast_queue_control(p->owner, AST_CONTROL_PROGRESS);
}
}
if (sipmethod == SIP_INVITE)
handle_response_invite(p, resp, rest, req, ignore, seqno);
break;
case 180: /* 180 Ringing */
if (sipmethod == SIP_INVITE) {
sip_cancel_destroy(p);
if (p->owner) {
ast_queue_control(p->owner, AST_CONTROL_RINGING);
if (p->owner->_state != AST_STATE_UP)
ast_setstate(p->owner, AST_STATE_RINGING);
}
}
if (sipmethod == SIP_INVITE)
handle_response_invite(p, resp, rest, req, ignore, seqno);
break;
case 200: /* 200 OK */
p->authtries = 0; /* Reset authentication counter */
@ -9157,52 +9285,14 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
}
}
} else if (sipmethod == SIP_INVITE) {
/* 200 OK on invite - someone's answering our call */
sip_cancel_destroy(p);
if (!ast_strlen_zero(get_header(req, "Content-Type")))
process_sdp(p, req);
/* Parse contact header for continued conversation */
/* When we get 200 OK, we now which device (and IP) to contact for this call */
/* This is important when we have a SIP proxy between us and the phone */
parse_ok_contact(p, req);
/* Save Record-Route for any later requests we make on this dialogue */
build_route(p, req, 1);
if (p->owner) {
if (p->owner->_state != AST_STATE_UP) {
#ifdef OSP_SUPPORT
time(&p->ospstart);
#endif
ast_queue_control(p->owner, AST_CONTROL_ANSWER);
ast_setstate(p->owner, AST_STATE_UP);
} else {
struct ast_frame af = { AST_FRAME_NULL, };
ast_queue_frame(p->owner, &af);
}
} else { /* It's possible we're getting an ACK after we've tried to disconnect by sending CANCEL */
ast_set_flag(p, SIP_PENDINGBYE);
}
ast_device_state_changed("SIP/%s", p->peername);
/* If I understand this right, the branch is different for a non-200 ACK only */
transmit_request(p, SIP_ACK, seqno, 0, 1);
check_pendings(p);
handle_response_invite(p, resp, rest, req, ignore, seqno);
} else if (sipmethod == SIP_REGISTER) {
res = handle_response_register(p, resp, rest, req, ignore, seqno);
}
break;
case 401: /* Not www-authorized on SIP method */
if (sipmethod == SIP_INVITE) {
/* First we ACK */
transmit_request(p, SIP_ACK, seqno, 0, 0);
/* Then we AUTH */
p->theirtag[0]='\0'; /* forget their old tag, so we don't match tags when getting response */
if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, "WWW-Authenticate", "Authorization", SIP_INVITE, 1)) {
ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
ast_set_flag(p, SIP_NEEDDESTROY);
ast_set_flag(p, SIP_ALREADYGONE);
if (p->owner)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
}
handle_response_invite(p, resp, rest, req, ignore, seqno);
} else if (p->registry && sipmethod == SIP_REGISTER) {
res = handle_response_register(p, resp, rest, req, ignore, seqno);
} else {
@ -9212,12 +9302,7 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
break;
case 403: /* Forbidden - we failed authentication */
if (sipmethod == SIP_INVITE) {
/* First we ACK */
transmit_request(p, SIP_ACK, seqno, 0, 0);
ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for INVITE to '%s'\n", get_header(&p->initreq, "From"));
if (owner)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
ast_set_flag(p, SIP_NEEDDESTROY);
handle_response_invite(p, resp, rest, req, ignore, seqno);
} else if (p->registry && sipmethod == SIP_REGISTER) {
res = handle_response_register(p, resp, rest, req, ignore, seqno);
} else {
@ -9227,25 +9312,14 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
case 404: /* Not found */
if (p->registry && sipmethod == SIP_REGISTER) {
res = handle_response_register(p, resp, rest, req, ignore, seqno);
} else if (sipmethod == SIP_INVITE) {
handle_response_invite(p, resp, rest, req, ignore, seqno);
} else if (owner)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
break;
case 407: /* Proxy auth required */
if (sipmethod == SIP_INVITE) {
/* First we ACK */
transmit_request(p, SIP_ACK, seqno, 0, 0);
/* Then we AUTH */
/* But only if the packet wasn't marked as ignore in handle_request */
if (!ignore){
p->theirtag[0]='\0'; /* forget their old tag, so we don't match tags when getting response */
if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", SIP_INVITE, 1)) {
ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
ast_set_flag(p, SIP_NEEDDESTROY);
if (p->owner)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
ast_set_flag(p, SIP_ALREADYGONE);
}
}
handle_response_invite(p, resp, rest, req, ignore, seqno);
} else if (sipmethod == SIP_BYE || sipmethod == SIP_REFER) {
if (ast_strlen_zero(p->authname))
ast_log(LOG_WARNING, "Asked to authenticate %s, to %s:%d but we have no matching peer!\n",
@ -9261,10 +9335,13 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
ast_set_flag(p, SIP_NEEDDESTROY);
break;
case 491: /* Pending */
if (sipmethod == SIP_INVITE) {
handle_response_invite(p, resp, rest, req, ignore, seqno);
}
case 501: /* Not Implemented */
if (sipmethod == SIP_INVITE) {
if (p->owner)
ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
handle_response_invite(p, resp, rest, req, ignore, seqno);
} else
ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), msg);
break;
@ -9304,11 +9381,9 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
snprintf(p->owner->call_forward, sizeof(p->owner->call_forward), "Local/%s@%s", p->username, p->context);
/* Fall through */
case 486: /* Busy here */
case 488: /* Not acceptable here - codec error */
case 600: /* Busy everywhere */
case 603: /* Decline */
if (p->owner)
ast_queue_control(p->owner, AST_CONTROL_BUSY);
break;
case 480: /* Temporarily Unavailable */
case 404: /* Not Found */
case 410: /* Gone */
@ -9346,27 +9421,63 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
} else {
/* Responses to OUTGOING SIP requests on INCOMING calls
get handled here. As well as out-of-call message responses */
if (sip_debug_test_pvt(p))
ast_verbose("Response message %s arrived\n", msg);
if (req->debug)
ast_verbose("SIP Response message for INCOMING dialog %s arrived\n", msg);
switch(resp) {
case 200:
/* Change branch since this is a 200 response */
if (sipmethod == SIP_INVITE) {
transmit_request(p, SIP_ACK, seqno, 0, 1);
p->authtries = 0;
handle_response_invite(p, resp, rest, req, ignore, seqno);
} else if (sipmethod == SIP_CANCEL) {
ast_log(LOG_DEBUG, "Got 200 OK on CANCEL\n");
} else if (sipmethod == SIP_MESSAGE)
/* We successfully transmitted a message */
ast_set_flag(p, SIP_NEEDDESTROY);
break;
case 401: /* www-auth */
case 407:
if (sipmethod == SIP_BYE || sipmethod == SIP_REFER) {
if (ast_strlen_zero(p->authname))
ast_log(LOG_WARNING, "Asked to authenticate %s, to %s:%d but we have no matching peer!\n",
msg, ast_inet_ntoa(iabuf, sizeof(iabuf), p->recv.sin_addr), ntohs(p->recv.sin_port));
if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, "Proxy-Authenticate", "Proxy-Authorization", sipmethod, 0)) {
char *auth, *auth2;
if (resp == 407) {
auth = "Proxy-Authenticate";
auth2 = "Proxy-Authorization";
} else {
auth = "WWW-Authenticate";
auth2 = "Authorization";
}
if ((p->authtries == MAX_AUTHTRIES) || do_proxy_auth(p, req, auth, auth2, sipmethod, 0)) {
ast_log(LOG_NOTICE, "Failed to authenticate on %s to '%s'\n", msg, get_header(&p->initreq, "From"));
ast_set_flag(p, SIP_NEEDDESTROY);
}
} else if (sipmethod == SIP_INVITE) {
handle_response_invite(p, resp, rest, req, ignore, seqno);
}
break;
case 481: /* Call leg does not exist */
if (sipmethod == SIP_INVITE) {
/* Re-invite failed */
handle_response_invite(p, resp, rest, req, ignore, seqno);
}
break;
default: /* Errors without handlers */
if ((resp >= 100) && (resp < 200)) {
if (sipmethod == SIP_INVITE) { /* re-invite */
sip_cancel_destroy(p);
}
}
if ((resp >= 300) && (resp < 700)) {
if ((option_verbose > 2) && (resp != 487))
ast_verbose(VERBOSE_PREFIX_3 "Incoming call: Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr));
switch(resp) {
case 488: /* Not acceptable here - codec error */
case 603: /* Decline */
case 500: /* Server error */
case 503: /* Service Unavailable */
if (sipmethod == SIP_INVITE) { /* re-invite failed */
sip_cancel_destroy(p);
}
break;
}
}
break;
}