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:
parent
721bd0aa59
commit
1bd1a35a9a
1 changed files with 205 additions and 94 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue